[evolution/account-mgmt: 2/33] Add ESourceConfig widget.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/account-mgmt: 2/33] Add ESourceConfig widget.
- Date: Fri, 18 Mar 2011 01:52:10 +0000 (UTC)
commit 16986b1ddb43cd6b390728111456f375d7e56f13
Author: Matthew Barnes <mbarnes redhat com>
Date: Fri Dec 17 17:45:54 2010 -0500
Add ESourceConfig widget.
Base class for building address book and calendar configuration dialogs.
addressbook/gui/widgets/Makefile.am | 2 +
addressbook/gui/widgets/e-book-source-config.c | 254 +++++++
addressbook/gui/widgets/e-book-source-config.h | 67 ++
calendar/gui/Makefile.am | 3 +
calendar/gui/e-cal-source-config.c | 394 ++++++++++
calendar/gui/e-cal-source-config.h | 76 ++
widgets/misc/Makefile.am | 29 +-
widgets/misc/e-interval-chooser.c | 214 ++++++
widgets/misc/e-interval-chooser.h | 68 ++
widgets/misc/e-source-config-backend.c | 140 ++++
widgets/misc/e-source-config-backend.h | 87 +++
widgets/misc/e-source-config-dialog.c | 244 ++++++
widgets/misc/e-source-config-dialog.h | 66 ++
widgets/misc/e-source-config.c | 933 ++++++++++++++++++++++++
widgets/misc/e-source-config.h | 93 +++
widgets/misc/test-source-config.c | 60 ++
16 files changed, 2728 insertions(+), 2 deletions(-)
---
diff --git a/addressbook/gui/widgets/Makefile.am b/addressbook/gui/widgets/Makefile.am
index 511876a..bbccbf4 100644
--- a/addressbook/gui/widgets/Makefile.am
+++ b/addressbook/gui/widgets/Makefile.am
@@ -49,6 +49,8 @@ libeabwidgets_la_SOURCES = \
e-addressbook-selector.h \
e-addressbook-view.c \
e-addressbook-view.h \
+ e-book-source-config.c \
+ e-book-source-config.h \
gal-view-minicard.c \
gal-view-minicard.h \
gal-view-factory-minicard.c \
diff --git a/addressbook/gui/widgets/e-book-source-config.c b/addressbook/gui/widgets/e-book-source-config.c
new file mode 100644
index 0000000..9802c05
--- /dev/null
+++ b/addressbook/gui/widgets/e-book-source-config.c
@@ -0,0 +1,254 @@
+/*
+ * e-book-source-config.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-book-source-config.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <libebook/e-source-address-book.h>
+#include <libedataserver/e-source-autocomplete.h>
+#include <libedataserver/e-source-offline.h>
+
+#define E_BOOK_SOURCE_CONFIG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_BOOK_SOURCE_CONFIG, EBookSourceConfigPrivate))
+
+struct _EBookSourceConfigPrivate {
+ GtkWidget *default_button;
+ GtkWidget *autocomplete_button;
+};
+
+G_DEFINE_TYPE (
+ EBookSourceConfig,
+ e_book_source_config,
+ E_TYPE_SOURCE_CONFIG)
+
+static ESource *
+book_source_config_get_default (ESourceConfig *config)
+{
+ ESourceRegistry *registry;
+
+ registry = e_source_config_get_registry (config);
+
+ return e_source_registry_get_default_address_book (registry);
+}
+
+static void
+book_source_config_set_default (ESourceConfig *config,
+ ESource *source)
+{
+ ESourceRegistry *registry;
+
+ registry = e_source_config_get_registry (config);
+
+ e_source_registry_set_default_address_book (registry, source);
+}
+
+static void
+book_source_config_dispose (GObject *object)
+{
+ EBookSourceConfigPrivate *priv;
+
+ priv = E_BOOK_SOURCE_CONFIG_GET_PRIVATE (object);
+
+ if (priv->default_button != NULL) {
+ g_object_unref (priv->default_button);
+ priv->default_button = NULL;
+ }
+
+ if (priv->autocomplete_button != NULL) {
+ g_object_unref (priv->autocomplete_button);
+ priv->autocomplete_button = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_book_source_config_parent_class)->dispose (object);
+}
+
+static void
+book_source_config_constructed (GObject *object)
+{
+ EBookSourceConfigPrivate *priv;
+ ESource *default_source;
+ ESource *original_source;
+ ESourceConfig *config;
+ GObjectClass *class;
+ GtkWidget *widget;
+ const gchar *label;
+
+ /* Chain up to parent's constructed() method. */
+ class = G_OBJECT_CLASS (e_book_source_config_parent_class);
+ class->constructed (object);
+
+ config = E_SOURCE_CONFIG (object);
+ priv = E_BOOK_SOURCE_CONFIG_GET_PRIVATE (object);
+
+ label = _("Mark as default address book");
+ widget = gtk_check_button_new_with_label (label);
+ priv->default_button = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ label = _("Autocomplete with this address book");
+ widget = gtk_check_button_new_with_label (label);
+ priv->autocomplete_button = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ default_source = book_source_config_get_default (config);
+ original_source = e_source_config_get_original_source (config);
+
+ if (original_source != NULL) {
+ gboolean active;
+
+ active = e_source_equal (original_source, default_source);
+ g_object_set (priv->default_button, "active", active, NULL);
+ }
+
+ e_source_config_insert_widget (
+ config, NULL, NULL, priv->default_button);
+
+ e_source_config_insert_widget (
+ config, NULL, NULL, priv->autocomplete_button);
+}
+
+static void
+book_source_config_init_candidate (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ EBookSourceConfigPrivate *priv;
+ ESourceConfigClass *class;
+ ESourceExtension *extension;
+ const gchar *extension_name;
+
+ /* Chain up to parent's init_candidate() method. */
+ class = E_SOURCE_CONFIG_CLASS (e_book_source_config_parent_class);
+ class->init_candidate (config, scratch_source);
+
+ priv = E_BOOK_SOURCE_CONFIG_GET_PRIVATE (config);
+
+ /* XXX Address book sources don't actually use any of the keys in
+ * the [Address Book] key file group, but it's the presence of
+ * the group itself that identifies the source as an address
+ * book, so make sure the address book extension is present in
+ * the scratch source. */
+ extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+ extension = e_source_get_extension (scratch_source, extension_name);
+
+ extension_name = E_SOURCE_EXTENSION_AUTOCOMPLETE;
+ extension = e_source_get_extension (scratch_source, extension_name);
+
+ g_object_bind_property (
+ extension, "include-me",
+ priv->autocomplete_button, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
+
+static void
+book_source_config_commit_changes (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ EBookSourceConfigPrivate *priv;
+ ESourceConfigClass *class;
+ ESource *default_source;
+ GtkToggleButton *toggle_button;
+
+ priv = E_BOOK_SOURCE_CONFIG_GET_PRIVATE (config);
+ toggle_button = GTK_TOGGLE_BUTTON (priv->default_button);
+
+ /* Chain up to parent's commit_changes() method. */
+ class = E_SOURCE_CONFIG_CLASS (e_book_source_config_parent_class);
+ class->commit_changes (config, scratch_source);
+
+ default_source = book_source_config_get_default (config);
+
+ /* The default setting is a little tricky to get right. If
+ * the toggle button is active, this ESource is now the default.
+ * That much is simple. But if the toggle button is NOT active,
+ * then we have to inspect the old default. If this ESource WAS
+ * the default, reset the default to 'system'. If this ESource
+ * WAS NOT the old default, leave it alone. */
+ if (gtk_toggle_button_get_active (toggle_button))
+ book_source_config_set_default (config, scratch_source);
+ else if (e_source_equal (scratch_source, default_source))
+ book_source_config_set_default (config, NULL);
+}
+
+static void
+e_book_source_config_class_init (EBookSourceConfigClass *class)
+{
+ GObjectClass *object_class;
+ ESourceConfigClass *source_config_class;
+
+ g_type_class_add_private (class, sizeof (EBookSourceConfigPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = book_source_config_dispose;
+ object_class->constructed = book_source_config_constructed;
+
+ source_config_class = E_SOURCE_CONFIG_CLASS (class);
+ source_config_class->init_candidate = book_source_config_init_candidate;
+ source_config_class->commit_changes = book_source_config_commit_changes;
+}
+
+static void
+e_book_source_config_init (EBookSourceConfig *config)
+{
+ config->priv = E_BOOK_SOURCE_CONFIG_GET_PRIVATE (config);
+}
+
+GtkWidget *
+e_book_source_config_new (ESourceRegistry *registry,
+ ESource *original_source)
+{
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+ if (original_source != NULL)
+ g_return_val_if_fail (E_IS_SOURCE (original_source), NULL);
+
+ return g_object_new (
+ E_TYPE_BOOK_SOURCE_CONFIG, "registry", registry,
+ "original-source", original_source, NULL);
+}
+
+void
+e_book_source_config_add_offline_toggle (EBookSourceConfig *config,
+ ESource *scratch_source)
+{
+ GtkWidget *widget;
+ ESourceExtension *extension;
+ const gchar *extension_name;
+
+ g_return_if_fail (E_IS_BOOK_SOURCE_CONFIG (config));
+ g_return_if_fail (E_IS_SOURCE (scratch_source));
+
+ extension_name = E_SOURCE_EXTENSION_OFFLINE;
+ extension = e_source_get_extension (scratch_source, extension_name);
+
+ widget = gtk_check_button_new_with_label (
+ _("Copy book content locally for offline operation"));
+ e_source_config_insert_widget (
+ E_SOURCE_CONFIG (config), scratch_source, NULL, widget);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ extension, "stay-synchronized",
+ widget, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
diff --git a/addressbook/gui/widgets/e-book-source-config.h b/addressbook/gui/widgets/e-book-source-config.h
new file mode 100644
index 0000000..18e0755
--- /dev/null
+++ b/addressbook/gui/widgets/e-book-source-config.h
@@ -0,0 +1,67 @@
+/*
+ * e-book-source-config.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_BOOK_SOURCE_CONFIG_H
+#define E_BOOK_SOURCE_CONFIG_H
+
+#include <misc/e-source-config.h>
+
+/* Standard GObject macros */
+#define E_TYPE_BOOK_SOURCE_CONFIG \
+ (e_book_source_config_get_type ())
+#define E_BOOK_SOURCE_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_BOOK_SOURCE_CONFIG, EBookSourceConfig))
+#define E_BOOK_SOURCE_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_BOOK_SOURCE_CONFIG, EBookSourceConfigClass))
+#define E_IS_BOOK_SOURCE_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_BOOK_SOURCE_CONFIG))
+#define E_IS_BOOK_SOURCE_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_BOOK_SOURCE_CONFIG))
+#define E_BOOK_SOURCE_CONFIG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_BOOK_SOURCE_CONFIG, EBookSourceConfigClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookSourceConfig EBookSourceConfig;
+typedef struct _EBookSourceConfigClass EBookSourceConfigClass;
+typedef struct _EBookSourceConfigPrivate EBookSourceConfigPrivate;
+
+struct _EBookSourceConfig {
+ ESourceConfig parent;
+ EBookSourceConfigPrivate *priv;
+};
+
+struct _EBookSourceConfigClass {
+ ESourceConfigClass parent_class;
+};
+
+GType e_book_source_config_get_type (void) G_GNUC_CONST;
+GtkWidget * e_book_source_config_new (ESourceRegistry *registry,
+ ESource *original_source);
+void e_book_source_config_add_offline_toggle
+ (EBookSourceConfig *config,
+ ESource *scratch_source);
+
+G_END_DECLS
+
+#endif /* E_BOOK_SOURCE_CONFIG_H */
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index a74d4a1..eac1aca 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -17,6 +17,7 @@ ecalendarinclude_HEADERS = \
e-cal-list-view.h \
e-cal-model-calendar.h \
e-cal-model.h \
+ e-cal-source-config.h \
e-calendar-selector.h \
e-calendar-view.h \
e-cell-date-edit-text.h \
@@ -113,6 +114,8 @@ libevolution_calendar_la_SOURCES = \
e-cal-model-memos.h \
e-cal-model-tasks.c \
e-cal-model-tasks.h \
+ e-cal-source-config.c \
+ e-cal-source-config.h \
e-calendar-selector.c \
e-calendar-selector.h \
e-calendar-view.c \
diff --git a/calendar/gui/e-cal-source-config.c b/calendar/gui/e-cal-source-config.c
new file mode 100644
index 0000000..a8e33e3
--- /dev/null
+++ b/calendar/gui/e-cal-source-config.c
@@ -0,0 +1,394 @@
+/*
+ * e-cal-source-config.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-cal-source-config.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <libecal/e-source-calendar.h>
+#include <libedataserver/e-source-offline.h>
+
+#include <e-util/e-util.h>
+
+#define E_CAL_SOURCE_CONFIG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SOURCE_CONFIG, ECalSourceConfigPrivate))
+
+struct _ECalSourceConfigPrivate {
+ ECalSourceType source_type;
+ GtkWidget *color_button;
+ GtkWidget *default_button;
+};
+
+enum {
+ PROP_0,
+ PROP_SOURCE_TYPE
+};
+
+G_DEFINE_TYPE (
+ ECalSourceConfig,
+ e_cal_source_config,
+ E_TYPE_SOURCE_CONFIG)
+
+static ESource *
+cal_source_config_get_default (ESourceConfig *config)
+{
+ ECalSourceConfigPrivate *priv;
+ ESourceRegistry *registry;
+
+ priv = E_CAL_SOURCE_CONFIG_GET_PRIVATE (config);
+ registry = e_source_config_get_registry (config);
+
+ if (priv->source_type == E_CAL_SOURCE_TYPE_EVENT)
+ return e_source_registry_get_default_calendar (registry);
+ else if (priv->source_type == E_CAL_SOURCE_TYPE_JOURNAL)
+ return e_source_registry_get_default_memo_list (registry);
+ else if (priv->source_type == E_CAL_SOURCE_TYPE_TODO)
+ return e_source_registry_get_default_task_list (registry);
+
+ g_return_val_if_reached (NULL);
+}
+
+static void
+cal_source_config_set_default (ESourceConfig *config,
+ ESource *source)
+{
+ ECalSourceConfigPrivate *priv;
+ ESourceRegistry *registry;
+
+ priv = E_CAL_SOURCE_CONFIG_GET_PRIVATE (config);
+ registry = e_source_config_get_registry (config);
+
+ if (priv->source_type == E_CAL_SOURCE_TYPE_EVENT)
+ e_source_registry_set_default_calendar (registry, source);
+ else if (priv->source_type == E_CAL_SOURCE_TYPE_JOURNAL)
+ e_source_registry_set_default_memo_list (registry, source);
+ else if (priv->source_type == E_CAL_SOURCE_TYPE_TODO)
+ e_source_registry_set_default_task_list (registry, source);
+}
+
+static void
+cal_source_config_set_source_type (ECalSourceConfig *config,
+ ECalSourceType source_type)
+{
+ config->priv->source_type = source_type;
+}
+
+static void
+cal_source_config_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE_TYPE:
+ cal_source_config_set_source_type (
+ E_CAL_SOURCE_CONFIG (object),
+ g_value_get_enum (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_source_config_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE_TYPE:
+ g_value_set_enum (
+ value,
+ e_cal_source_config_get_source_type (
+ E_CAL_SOURCE_CONFIG (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_source_config_dispose (GObject *object)
+{
+ ECalSourceConfigPrivate *priv;
+
+ priv = E_CAL_SOURCE_CONFIG_GET_PRIVATE (object);
+
+ if (priv->color_button != NULL) {
+ g_object_unref (priv->color_button);
+ priv->color_button = NULL;
+ }
+
+ if (priv->default_button != NULL) {
+ g_object_unref (priv->default_button);
+ priv->default_button = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_cal_source_config_parent_class)->dispose (object);
+}
+
+static void
+cal_source_config_constructed (GObject *object)
+{
+ ECalSourceConfigPrivate *priv;
+ ESource *default_source;
+ ESource *original_source;
+ ESourceConfig *config;
+ GObjectClass *class;
+ GtkWidget *widget;
+ const gchar *label;
+
+ /* Chain up to parent's constructed() method. */
+ class = G_OBJECT_CLASS (e_cal_source_config_parent_class);
+ class->constructed (object);
+
+ config = E_SOURCE_CONFIG (object);
+ priv = E_CAL_SOURCE_CONFIG_GET_PRIVATE (object);
+
+ widget = gtk_color_button_new ();
+ priv->color_button = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ switch (priv->source_type) {
+ case E_CAL_SOURCE_TYPE_EVENT:
+ label = _("Mark as default calendar");
+ break;
+ case E_CAL_SOURCE_TYPE_TODO:
+ label = _("Mark as default task list");
+ break;
+ case E_CAL_SOURCE_TYPE_JOURNAL:
+ label = _("Mark as default memo list");
+ break;
+ default:
+ /* No need to translate this string. */
+ label = "Invalid ECalSourceType value";
+ g_warn_if_reached ();
+ }
+
+ widget = gtk_check_button_new_with_label (label);
+ priv->default_button = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ default_source = cal_source_config_get_default (config);
+ original_source = e_source_config_get_original_source (config);
+
+ if (original_source != NULL) {
+ gboolean active;
+
+ active = e_source_equal (original_source, default_source);
+ g_object_set (priv->default_button, "active", active, NULL);
+ }
+
+ e_source_config_insert_widget (
+ config, NULL, _("Color:"), priv->color_button);
+
+ e_source_config_insert_widget (
+ config, NULL, NULL, priv->default_button);
+}
+
+static void
+cal_source_config_init_candidate (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ ECalSourceConfigPrivate *priv;
+ ESourceConfigClass *class;
+ ESourceExtension *extension;
+
+ /* Chain up to parent's init_candidate() method. */
+ class = E_SOURCE_CONFIG_CLASS (e_cal_source_config_parent_class);
+ class->init_candidate (config, scratch_source);
+
+ priv = E_CAL_SOURCE_CONFIG_GET_PRIVATE (config);
+
+ extension = e_cal_source_config_get_selectable (
+ E_CAL_SOURCE_CONFIG (config), scratch_source);
+
+ g_object_bind_property_full (
+ extension, "color",
+ priv->color_button, "color",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE,
+ e_binding_transform_string_to_color,
+ e_binding_transform_color_to_string,
+ NULL, (GDestroyNotify) NULL);
+}
+
+static void
+cal_source_config_commit_changes (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ ECalSourceConfigPrivate *priv;
+ GtkToggleButton *toggle_button;
+ ESourceConfigClass *class;
+ ESource *default_source;
+
+ priv = E_CAL_SOURCE_CONFIG_GET_PRIVATE (config);
+ toggle_button = GTK_TOGGLE_BUTTON (priv->default_button);
+
+ /* Chain up to parent's commit_changes() method. */
+ class = E_SOURCE_CONFIG_CLASS (e_cal_source_config_parent_class);
+ class->commit_changes (config, scratch_source);
+
+ default_source = cal_source_config_get_default (config);
+
+ /* The default setting is a little tricky to get right. If
+ * the toggle button is active, this ESource is now the default.
+ * That much is simple. But if the toggle button is NOT active,
+ * then we have to inspect the old default. If this ESource WAS
+ * the default, reset the default to 'system'. If this ESource
+ * WAS NOT the old default, leave it alone. */
+ if (gtk_toggle_button_get_active (toggle_button))
+ cal_source_config_set_default (config, scratch_source);
+ else if (e_source_equal (scratch_source, default_source))
+ cal_source_config_set_default (config, NULL);
+}
+
+static void
+e_cal_source_config_class_init (ECalSourceConfigClass *class)
+{
+ GObjectClass *object_class;
+ ESourceConfigClass *source_config_class;
+
+ g_type_class_add_private (class, sizeof (ECalSourceConfigPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = cal_source_config_set_property;
+ object_class->get_property = cal_source_config_get_property;
+ object_class->dispose = cal_source_config_dispose;
+ object_class->constructed = cal_source_config_constructed;
+
+ source_config_class = E_SOURCE_CONFIG_CLASS (class);
+ source_config_class->init_candidate = cal_source_config_init_candidate;
+ source_config_class->commit_changes = cal_source_config_commit_changes;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SOURCE_TYPE,
+ g_param_spec_enum (
+ "source-type",
+ "Source Type",
+ "The iCalendar object type",
+ E_TYPE_CAL_SOURCE_TYPE,
+ E_CAL_SOURCE_TYPE_EVENT,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_cal_source_config_init (ECalSourceConfig *config)
+{
+ config->priv = E_CAL_SOURCE_CONFIG_GET_PRIVATE (config);
+}
+
+GtkWidget *
+e_cal_source_config_new (ESourceRegistry *registry,
+ ESource *original_source,
+ ECalSourceType source_type)
+{
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+ if (original_source != NULL)
+ g_return_val_if_fail (E_IS_SOURCE (original_source), NULL);
+
+ return g_object_new (
+ E_TYPE_CAL_SOURCE_CONFIG, "registry", registry,
+ "original-source", original_source, "source-type",
+ source_type, NULL);
+}
+
+ESourceExtension *
+e_cal_source_config_get_selectable (ECalSourceConfig *config,
+ ESource *scratch_source)
+{
+ const gchar *extension_name;
+
+ g_return_val_if_fail (E_IS_CAL_SOURCE_CONFIG (config), NULL);
+
+ switch (e_cal_source_config_get_source_type (config)) {
+ case E_CAL_SOURCE_TYPE_EVENT:
+ extension_name = E_SOURCE_EXTENSION_CALENDAR;
+ break;
+ case E_CAL_SOURCE_TYPE_TODO:
+ extension_name = E_SOURCE_EXTENSION_TASK_LIST;
+ break;
+ case E_CAL_SOURCE_TYPE_JOURNAL:
+ extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ return e_source_get_extension (scratch_source, extension_name);
+}
+
+ECalSourceType
+e_cal_source_config_get_source_type (ECalSourceConfig *config)
+{
+ g_return_val_if_fail (E_IS_CAL_SOURCE_CONFIG (config), 0);
+
+ return config->priv->source_type;
+}
+
+void
+e_cal_source_config_add_offline_toggle (ECalSourceConfig *config,
+ ESource *scratch_source)
+{
+ GtkWidget *widget;
+ ESourceExtension *extension;
+ const gchar *extension_name;
+ const gchar *label;
+
+ g_return_if_fail (E_IS_CAL_SOURCE_CONFIG (config));
+ g_return_if_fail (E_IS_SOURCE (scratch_source));
+
+ extension_name = E_SOURCE_EXTENSION_OFFLINE;
+ extension = e_source_get_extension (scratch_source, extension_name);
+
+ switch (e_cal_source_config_get_source_type (config)) {
+ case E_CAL_SOURCE_TYPE_EVENT:
+ label = _("Copy calendar contents locally "
+ "for offline operation");
+ break;
+ case E_CAL_SOURCE_TYPE_TODO:
+ label = _("Copy task list contents locally "
+ "for offline operation");
+ break;
+ case E_CAL_SOURCE_TYPE_JOURNAL:
+ label = _("Copy memo list contents locally "
+ "for offline operation");
+ break;
+ default:
+ g_return_if_reached ();
+ }
+
+ widget = gtk_check_button_new_with_label (label);
+ e_source_config_insert_widget (
+ E_SOURCE_CONFIG (config), scratch_source, NULL, widget);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ extension, "stay-synchronized",
+ widget, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
diff --git a/calendar/gui/e-cal-source-config.h b/calendar/gui/e-cal-source-config.h
new file mode 100644
index 0000000..ce4e11d
--- /dev/null
+++ b/calendar/gui/e-cal-source-config.h
@@ -0,0 +1,76 @@
+/*
+ * e-cal-source-config.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_CAL_SOURCE_CONFIG_H
+#define E_CAL_SOURCE_CONFIG_H
+
+#include <libecal/e-cal.h>
+#include <misc/e-source-config.h>
+#include <libedataserver/e-source-extension.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SOURCE_CONFIG \
+ (e_cal_source_config_get_type ())
+#define E_CAL_SOURCE_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SOURCE_CONFIG, ECalSourceConfig))
+#define E_CAL_SOURCE_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SOURCE_CONFIG, ECalSourceConfigClass))
+#define E_IS_CAL_SOURCE_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SOURCE_CONFIG))
+#define E_IS_CAL_SOURCE_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SOURCE_CONFIG))
+#define E_CAL_SOURCE_CONFIG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SOURCE_CONFIG, ECalSourceConfigClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalSourceConfig ECalSourceConfig;
+typedef struct _ECalSourceConfigClass ECalSourceConfigClass;
+typedef struct _ECalSourceConfigPrivate ECalSourceConfigPrivate;
+
+struct _ECalSourceConfig {
+ ESourceConfig parent;
+ ECalSourceConfigPrivate *priv;
+};
+
+struct _ECalSourceConfigClass {
+ ESourceConfigClass parent_class;
+};
+
+GType e_cal_source_config_get_type (void) G_GNUC_CONST;
+GtkWidget * e_cal_source_config_new (ESourceRegistry *registry,
+ ESource *original_source,
+ ECalSourceType source_type);
+ESourceExtension *
+ e_cal_source_config_get_selectable
+ (ECalSourceConfig *config,
+ ESource *scratch_source);
+ECalSourceType e_cal_source_config_get_source_type
+ (ECalSourceConfig *config);
+void e_cal_source_config_add_offline_toggle
+ (ECalSourceConfig *config,
+ ESource *scratch_source);
+
+G_END_DECLS
+
+#endif /* E_CAL_SOURCE_CONFIG_H */
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index 7e9ce9c..57c7101 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -39,6 +39,7 @@ widgetsinclude_HEADERS = \
e-hsv-utils.h \
e-image-chooser.h \
e-import-assistant.h \
+ e-interval-chooser.h \
e-map.h \
e-menu-tool-action.h \
e-menu-tool-button.h \
@@ -63,6 +64,9 @@ widgetsinclude_HEADERS = \
e-signature-preview.h \
e-signature-script-dialog.h \
e-signature-tree-view.h \
+ e-source-config.h \
+ e-source-config-backend.h \
+ e-source-config-dialog.h \
e-url-entry.h \
e-web-view.h \
e-web-view-preview.h \
@@ -118,6 +122,7 @@ libemiscwidgets_la_SOURCES = \
e-hsv-utils.c \
e-image-chooser.c \
e-import-assistant.c \
+ e-interval-chooser.c \
e-map.c \
e-menu-tool-action.c \
e-menu-tool-button.c \
@@ -142,6 +147,9 @@ libemiscwidgets_la_SOURCES = \
e-signature-preview.c \
e-signature-script-dialog.c \
e-signature-tree-view.c \
+ e-source-config.c \
+ e-source-config-backend.c \
+ e-source-config-dialog.c \
e-url-entry.c \
e-web-view.c \
e-web-view-preview.c \
@@ -165,16 +173,18 @@ libemiscwidgets_la_LIBADD = \
noinst_PROGRAMS = \
test-calendar \
test-dateedit \
- test-preferences-window
+ test-preferences-window \
+ test-source-config
test_widgets_misc_CPPFLAGS= \
$(AM_CPPFLAGS) \
-I$(top_srcdir) \
-I$(top_srcdir)/filter \
-I$(top_srcdir)/widgets \
- -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\" \
-DG_LOG_DOMAIN=__FILE__ \
$(EVOLUTION_MAIL_CFLAGS) \
+ $(EVOLUTION_DATA_SERVER_CFLAGS) \
$(GNOME_PLATFORM_CFLAGS)
# test-calendar
@@ -219,6 +229,21 @@ test_preferences_window_LDADD = \
$(GNOME_PLATFORM_LIBS) \
$(E_WIDGETS_LIBS)
+# test-source-config
+
+test_source_config_CPPFLAGS = $(test_widgets_misc_CPPFLAGS)
+
+test_source_config_SOURCES = \
+ test-source-config.c
+
+test_source_config_LDADD = \
+ libemiscwidgets.la \
+ $(top_builddir)/e-util/libeutil.la \
+ $(top_builddir)/filter/libfilter.la \
+ $(GNOME_PLATFORM_LIBS) \
+ $(EVOLUTION_DATA_SERVER_LIBS) \
+ $(E_WIDGETS_LIBS)
+
EXTRA_DIST = $(ui_DATA)
-include $(top_srcdir)/git.mk
diff --git a/widgets/misc/e-interval-chooser.c b/widgets/misc/e-interval-chooser.c
new file mode 100644
index 0000000..5a2b4e0
--- /dev/null
+++ b/widgets/misc/e-interval-chooser.c
@@ -0,0 +1,214 @@
+/*
+ * e-interval-chooser.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-interval-chooser.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-util.h>
+
+#define E_INTERVAL_CHOOSER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_INTERVAL_CHOOSER, EIntervalChooserPrivate))
+
+#define MINUTES_PER_HOUR (60)
+#define MINUTES_PER_DAY (MINUTES_PER_HOUR * 24)
+
+struct _EIntervalChooserPrivate {
+ GtkComboBox *combo_box; /* not referenced */
+ GtkSpinButton *spin_button; /* not referenced */
+};
+
+enum {
+ PROP_0,
+ PROP_INTERVAL_MINUTES
+};
+
+G_DEFINE_TYPE (
+ EIntervalChooser,
+ e_interval_chooser,
+ GTK_TYPE_BOX)
+
+static void
+interval_chooser_notify_interval (GObject *object)
+{
+ g_object_notify (object, "interval-minutes");
+}
+
+static void
+interval_chooser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_INTERVAL_MINUTES:
+ e_interval_chooser_set_interval_minutes (
+ E_INTERVAL_CHOOSER (object),
+ g_value_get_uint (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+interval_chooser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_INTERVAL_MINUTES:
+ g_value_set_uint (
+ value,
+ e_interval_chooser_get_interval_minutes (
+ E_INTERVAL_CHOOSER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_interval_chooser_class_init (EIntervalChooserClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (EIntervalChooserPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = interval_chooser_set_property;
+ object_class->get_property = interval_chooser_get_property;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_INTERVAL_MINUTES,
+ g_param_spec_uint (
+ "interval-minutes",
+ "Interval in Minutes",
+ "Refresh interval in minutes",
+ 0, G_MAXUINT, 60,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_interval_chooser_init (EIntervalChooser *chooser)
+{
+ GtkWidget *widget;
+
+ chooser->priv = E_INTERVAL_CHOOSER_GET_PRIVATE (chooser);
+
+ gtk_orientable_set_orientation (
+ GTK_ORIENTABLE (chooser), GTK_ORIENTATION_HORIZONTAL);
+
+ gtk_box_set_spacing (GTK_BOX (chooser), 6);
+
+ widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (widget), TRUE);
+ gtk_spin_button_set_update_policy (
+ GTK_SPIN_BUTTON (widget), GTK_UPDATE_IF_VALID);
+ gtk_box_pack_start (GTK_BOX (chooser), widget, TRUE, TRUE, 0);
+ chooser->priv->spin_button = GTK_SPIN_BUTTON (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "notify::value",
+ G_CALLBACK (interval_chooser_notify_interval), chooser);
+
+ widget = gtk_combo_box_text_new ();
+ gtk_combo_box_text_append_text (
+ GTK_COMBO_BOX_TEXT (widget), _("minutes"));
+ gtk_combo_box_text_append_text (
+ GTK_COMBO_BOX_TEXT (widget), _("hours"));
+ gtk_combo_box_text_append_text (
+ GTK_COMBO_BOX_TEXT (widget), _("days"));
+ gtk_box_pack_start (GTK_BOX (chooser), widget, FALSE, FALSE, 0);
+ chooser->priv->combo_box = GTK_COMBO_BOX (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "notify::active",
+ G_CALLBACK (interval_chooser_notify_interval), chooser);
+}
+
+GtkWidget *
+e_interval_chooser_new (void)
+{
+ return g_object_new (E_TYPE_INTERVAL_CHOOSER, NULL);
+}
+
+guint
+e_interval_chooser_get_interval_minutes (EIntervalChooser *chooser)
+{
+ EDurationType units;
+ gdouble interval_minutes;
+
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG_REFRESH (chooser), 0);
+
+ units = gtk_combo_box_get_active (chooser->priv->combo_box);
+
+ interval_minutes = gtk_spin_button_get_value (
+ chooser->priv->spin_button);
+
+ switch (units) {
+ case E_DURATION_HOURS:
+ interval_minutes *= MINUTES_PER_HOUR;
+ break;
+ case E_DURATION_DAYS:
+ interval_minutes *= MINUTES_PER_DAY;
+ break;
+ default:
+ break;
+ }
+
+ return (guint) interval_minutes;
+}
+
+void
+e_interval_chooser_set_interval_minutes (EIntervalChooser *chooser,
+ guint interval_minutes)
+{
+ EDurationType units;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG_REFRESH (chooser));
+
+ if (interval_minutes == 0) {
+ units = E_DURATION_MINUTES;
+ } else if (interval_minutes % MINUTES_PER_DAY == 0) {
+ interval_minutes /= MINUTES_PER_DAY;
+ units = E_DURATION_DAYS;
+ } else if (interval_minutes % MINUTES_PER_HOUR == 0) {
+ interval_minutes /= MINUTES_PER_HOUR;
+ units = E_DURATION_HOURS;
+ } else {
+ units = E_DURATION_MINUTES;
+ }
+
+ g_object_freeze_notify (G_OBJECT (chooser));
+
+ gtk_combo_box_set_active (chooser->priv->combo_box, units);
+
+ gtk_spin_button_set_value (
+ chooser->priv->spin_button, interval_minutes);
+
+ g_object_thaw_notify (G_OBJECT (chooser));
+}
diff --git a/widgets/misc/e-interval-chooser.h b/widgets/misc/e-interval-chooser.h
new file mode 100644
index 0000000..351cbbe
--- /dev/null
+++ b/widgets/misc/e-interval-chooser.h
@@ -0,0 +1,68 @@
+/*
+ * e-interval-chooser.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_INTERVAL_CHOOSER_H
+#define E_INTERVAL_CHOOSER_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_INTERVAL_CHOOSER \
+ (e_interval_chooser_get_type ())
+#define E_INTERVAL_CHOOSER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_INTERVAL_CHOOSER, EIntervalChooser))
+#define E_INTERVAL_CHOOSER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_INTERVAL_CHOOSER, EIntervalChooserClass))
+#define E_IS_SOURCE_CONFIG_REFRESH(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_INTERVAL_CHOOSER))
+#define E_IS_SOURCE_CONFIG_REFRESH_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_INTERVAL_CHOOSER))
+#define E_INTERVAL_CHOOSER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_INTERVAL_CHOOSER, EIntervalChooserClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EIntervalChooser EIntervalChooser;
+typedef struct _EIntervalChooserClass EIntervalChooserClass;
+typedef struct _EIntervalChooserPrivate EIntervalChooserPrivate;
+
+struct _EIntervalChooser {
+ GtkBox parent;
+ EIntervalChooserPrivate *priv;
+};
+
+struct _EIntervalChooserClass {
+ GtkBoxClass parent_class;
+};
+
+GType e_interval_chooser_get_type (void) G_GNUC_CONST;
+GtkWidget * e_interval_chooser_new (void);
+guint e_interval_chooser_get_interval_minutes
+ (EIntervalChooser *refresh);
+void e_interval_chooser_set_interval_minutes
+ (EIntervalChooser *refresh,
+ guint interval_minutes);
+
+G_END_DECLS
+
+#endif /* E_INTERVAL_CHOOSER_H */
diff --git a/widgets/misc/e-source-config-backend.c b/widgets/misc/e-source-config-backend.c
new file mode 100644
index 0000000..e6802f9
--- /dev/null
+++ b/widgets/misc/e-source-config-backend.c
@@ -0,0 +1,140 @@
+/*
+ * e-source-config-backend.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-config-backend.h"
+
+G_DEFINE_TYPE (
+ ESourceConfigBackend,
+ e_source_config_backend,
+ E_TYPE_EXTENSION)
+
+static gboolean
+source_config_backend_allow_creation (ESourceConfigBackend *backend)
+{
+ return TRUE;
+}
+
+static void
+source_config_backend_insert_widgets (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ /* does nothing */
+}
+
+static gboolean
+source_config_backend_check_complete (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ return TRUE;
+}
+
+static void
+source_config_backend_commit_changes (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ /* does nothing */
+}
+
+static void
+e_source_config_backend_class_init (ESourceConfigBackendClass *class)
+{
+ EExtensionClass *extension_class;
+
+ extension_class = E_EXTENSION_CLASS (class);
+ extension_class->extensible_type = E_TYPE_SOURCE_CONFIG;
+
+ class->allow_creation = source_config_backend_allow_creation;
+ class->insert_widgets = source_config_backend_insert_widgets;
+ class->check_complete = source_config_backend_check_complete;
+ class->commit_changes = source_config_backend_commit_changes;
+}
+
+static void
+e_source_config_backend_init (ESourceConfigBackend *backend)
+{
+}
+
+ESourceConfig *
+e_source_config_backend_get_config (ESourceConfigBackend *backend)
+{
+ EExtensible *extensible;
+
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG_BACKEND (backend), NULL);
+
+ extensible = e_extension_get_extensible (E_EXTENSION (backend));
+
+ return E_SOURCE_CONFIG (extensible);
+}
+
+gboolean
+e_source_config_backend_allow_creation (ESourceConfigBackend *backend)
+{
+ ESourceConfigBackendClass *class;
+
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG_BACKEND (backend), FALSE);
+
+ class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
+ g_return_val_if_fail (class->allow_creation != NULL, FALSE);
+
+ return class->allow_creation (backend);
+}
+
+void
+e_source_config_backend_insert_widgets (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ ESourceConfigBackendClass *class;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG_BACKEND (backend));
+ g_return_if_fail (E_IS_SOURCE (scratch_source));
+
+ class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->insert_widgets != NULL);
+
+ class->insert_widgets (backend, scratch_source);
+}
+
+gboolean
+e_source_config_backend_check_complete (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ ESourceConfigBackendClass *class;
+
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG_BACKEND (backend), FALSE);
+ g_return_val_if_fail (E_IS_SOURCE (scratch_source), FALSE);
+
+ class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
+ g_return_val_if_fail (class->check_complete != NULL, FALSE);
+
+ return class->check_complete (backend, scratch_source);
+}
+
+void
+e_source_config_backend_commit_changes (ESourceConfigBackend *backend,
+ ESource *scratch_source)
+{
+ ESourceConfigBackendClass *class;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG_BACKEND (backend));
+ g_return_if_fail (E_IS_SOURCE (scratch_source));
+
+ class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
+ g_return_if_fail (class->commit_changes != NULL);
+
+ class->commit_changes (backend, scratch_source);
+}
diff --git a/widgets/misc/e-source-config-backend.h b/widgets/misc/e-source-config-backend.h
new file mode 100644
index 0000000..8e2275e
--- /dev/null
+++ b/widgets/misc/e-source-config-backend.h
@@ -0,0 +1,87 @@
+/*
+ * e-source-config-backend.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_CONFIG_BACKEND_H
+#define E_SOURCE_CONFIG_BACKEND_H
+
+#include <e-util/e-extension.h>
+#include <misc/e-source-config.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CONFIG_BACKEND \
+ (e_source_config_backend_get_type ())
+#define E_SOURCE_CONFIG_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SOURCE_CONFIG_BACKEND, ESourceConfigBackend))
+#define E_SOURCE_CONFIG_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SOURCE_CONFIG_BACKEND, ESourceConfigBackendClass))
+#define E_IS_SOURCE_CONFIG_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SOURCE_CONFIG_BACKEND))
+#define E_IS_SOURCE_CONFIG_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SOURCE_CONFIG_BACKEND))
+#define E_SOURCE_CONFIG_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SOURCE_CONFIG_BACKEND, ESourceConfigBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceConfigBackend ESourceConfigBackend;
+typedef struct _ESourceConfigBackendClass ESourceConfigBackendClass;
+typedef struct _ESourceConfigBackendPrivate ESourceConfigBackendPrivate;
+
+struct _ESourceConfigBackend {
+ EExtension parent;
+ ESourceConfigBackendPrivate *priv;
+};
+
+struct _ESourceConfigBackendClass {
+ EExtensionClass parent_class;
+
+ const gchar *backend_name;
+
+ gboolean (*allow_creation) (ESourceConfigBackend *backend);
+ void (*insert_widgets) (ESourceConfigBackend *backend,
+ ESource *scratch_source);
+ gboolean (*check_complete) (ESourceConfigBackend *backend,
+ ESource *scratch_source);
+ void (*commit_changes) (ESourceConfigBackend *backend,
+ ESource *scratch_source);
+};
+
+GType e_source_config_backend_get_type
+ (void) G_GNUC_CONST;
+ESourceConfig * e_source_config_backend_get_config
+ (ESourceConfigBackend *backend);
+gboolean e_source_config_backend_allow_creation
+ (ESourceConfigBackend *backend);
+void e_source_config_backend_insert_widgets
+ (ESourceConfigBackend *backend,
+ ESource *scratch_source);
+gboolean e_source_config_backend_check_complete
+ (ESourceConfigBackend *backend,
+ ESource *scratch_source);
+void e_source_config_backend_commit_changes
+ (ESourceConfigBackend *backend,
+ ESource *scratch_source);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_CONFIG_BACKEND_H */
diff --git a/widgets/misc/e-source-config-dialog.c b/widgets/misc/e-source-config-dialog.c
new file mode 100644
index 0000000..f898c9d
--- /dev/null
+++ b/widgets/misc/e-source-config-dialog.c
@@ -0,0 +1,244 @@
+/*
+ * e-source-config-dialog.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-config-dialog.h"
+
+#define E_SOURCE_CONFIG_DIALOG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SOURCE_CONFIG_DIALOG, ESourceConfigDialogPrivate))
+
+struct _ESourceConfigDialogPrivate {
+ ESourceConfig *config;
+ ESourceRegistry *registry;
+};
+
+enum {
+ PROP_0,
+ PROP_CONFIG
+};
+
+G_DEFINE_TYPE (
+ ESourceConfigDialog,
+ e_source_config_dialog,
+ GTK_TYPE_DIALOG)
+
+static void
+source_config_dialog_source_removed_cb (ESourceRegistry *registry,
+ ESource *removed_source,
+ ESourceConfigDialog *dialog)
+{
+ ESourceConfig *config;
+ ESource *original_source;
+
+ /* If the ESource being edited is removed, cancel the dialog. */
+
+ config = e_source_config_dialog_get_config (dialog);
+ original_source = e_source_config_get_original_source (config);
+
+ if (original_source == NULL)
+ return;
+
+ if (!e_source_equal (original_source, removed_source))
+ return;
+
+ gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+}
+
+static void
+source_config_dialog_set_config (ESourceConfigDialog *dialog,
+ ESourceConfig *config)
+{
+ ESourceRegistry *registry;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG (config));
+ g_return_if_fail (dialog->priv->config == NULL);
+
+ dialog->priv->config = g_object_ref (config);
+
+ registry = e_source_config_get_registry (config);
+ dialog->priv->registry = g_object_ref (registry);
+
+ g_signal_connect (
+ registry, "source-removed",
+ G_CALLBACK (source_config_dialog_source_removed_cb), dialog);
+}
+
+static void
+source_config_dialog_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONFIG:
+ source_config_dialog_set_config (
+ E_SOURCE_CONFIG_DIALOG (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_config_dialog_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CONFIG:
+ g_value_set_object (
+ value,
+ e_source_config_dialog_get_config (
+ E_SOURCE_CONFIG_DIALOG (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_config_dialog_dispose (GObject *object)
+{
+ ESourceConfigDialogPrivate *priv;
+
+ priv = E_SOURCE_CONFIG_DIALOG_GET_PRIVATE (object);
+
+ if (priv->config != NULL) {
+ g_object_unref (priv->config);
+ priv->config = 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;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_source_config_dialog_parent_class)->dispose (object);
+}
+
+static void
+source_config_dialog_constructed (GObject *object)
+{
+ ESourceConfigDialogPrivate *priv;
+ GtkWidget *content_area;
+ GtkWidget *config;
+ GtkWidget *widget;
+
+ priv = E_SOURCE_CONFIG_DIALOG_GET_PRIVATE (object);
+
+ config = GTK_WIDGET (priv->config);
+
+ widget = gtk_dialog_get_widget_for_response (
+ GTK_DIALOG (object), GTK_RESPONSE_OK);
+
+ gtk_container_set_border_width (GTK_CONTAINER (object), 5);
+ gtk_container_set_border_width (GTK_CONTAINER (config), 5);
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (object));
+ gtk_box_pack_start (GTK_BOX (content_area), config, TRUE, TRUE, 0);
+ gtk_widget_show (config);
+
+ /* Don't use G_BINDING_SYNC_CREATE here. The ESourceConfig widget
+ * is not ready to run check_complete() until after it's realized. */
+ g_object_bind_property (
+ config, "complete",
+ widget, "sensitive",
+ G_BINDING_DEFAULT);
+}
+
+static void
+source_config_dialog_response (GtkDialog *dialog,
+ gint response_id)
+{
+ ESourceConfigDialogPrivate *priv;
+
+ priv = E_SOURCE_CONFIG_DIALOG_GET_PRIVATE (dialog);
+
+ if (response_id == GTK_RESPONSE_OK)
+ e_source_config_commit_changes (priv->config);
+}
+
+static void
+e_source_config_dialog_class_init (ESourceConfigDialogClass *class)
+{
+ GObjectClass *object_class;
+ GtkDialogClass *dialog_class;
+
+ g_type_class_add_private (class, sizeof (ESourceConfigDialogPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = source_config_dialog_set_property;
+ object_class->get_property = source_config_dialog_get_property;
+ object_class->dispose = source_config_dialog_dispose;
+ object_class->constructed = source_config_dialog_constructed;
+
+ dialog_class = GTK_DIALOG_CLASS (class);
+ dialog_class->response = source_config_dialog_response;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CONFIG,
+ g_param_spec_object (
+ "config",
+ "Config",
+ "The ESourceConfig instance",
+ E_TYPE_SOURCE_CONFIG,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_source_config_dialog_init (ESourceConfigDialog *dialog)
+{
+ dialog->priv = E_SOURCE_CONFIG_DIALOG_GET_PRIVATE (dialog);
+
+ gtk_dialog_add_buttons (
+ GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+}
+
+GtkWidget *
+e_source_config_dialog_new (ESourceConfig *config,
+ GtkWindow *parent)
+{
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
+
+ return g_object_new (
+ E_TYPE_SOURCE_CONFIG_DIALOG,
+ "config", config, "transient-for", parent, NULL);
+}
+
+ESourceConfig *
+e_source_config_dialog_get_config (ESourceConfigDialog *dialog)
+{
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG_DIALOG (dialog), NULL);
+
+ return dialog->priv->config;
+}
diff --git a/widgets/misc/e-source-config-dialog.h b/widgets/misc/e-source-config-dialog.h
new file mode 100644
index 0000000..eaa602b
--- /dev/null
+++ b/widgets/misc/e-source-config-dialog.h
@@ -0,0 +1,66 @@
+/*
+ * e-source-config-dialog.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_CONFIG_DIALOG_H
+#define E_SOURCE_CONFIG_DIALOG_H
+
+#include <misc/e-source-config.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CONFIG_DIALOG \
+ (e_source_config_dialog_get_type ())
+#define E_SOURCE_CONFIG_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SOURCE_CONFIG_DIALOG, ESourceConfigDialog))
+#define E_SOURCE_CONFIG_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SOURCE_CONFIG_DIALOG, ESourceConfigDialogClass))
+#define E_IS_SOURCE_CONFIG_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SOURCE_CONFIG_DIALOG))
+#define E_IS_SOURCE_CONFIG_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SOURCE_CONFIG_DIALOG))
+#define E_SOURCE_CONFIG_DIALOG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SOURCE_CONFIG_DIALOG, ESourceConfigDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceConfigDialog ESourceConfigDialog;
+typedef struct _ESourceConfigDialogClass ESourceConfigDialogClass;
+typedef struct _ESourceConfigDialogPrivate ESourceConfigDialogPrivate;
+
+struct _ESourceConfigDialog {
+ GtkDialog parent;
+ ESourceConfigDialogPrivate *priv;
+};
+
+struct _ESourceConfigDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType e_source_config_dialog_get_type (void) G_GNUC_CONST;
+GtkWidget * e_source_config_dialog_new (ESourceConfig *config,
+ GtkWindow *parent);
+ESourceConfig * e_source_config_dialog_get_config
+ (ESourceConfigDialog *dialog);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_CONFIG_DIALOG_H */
diff --git a/widgets/misc/e-source-config.c b/widgets/misc/e-source-config.c
new file mode 100644
index 0000000..3120d13
--- /dev/null
+++ b/widgets/misc/e-source-config.c
@@ -0,0 +1,933 @@
+/*
+ * e-source-config.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-source-config.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/e-source-refresh.h>
+#include <libedataserver/e-source-security.h>
+
+#include <e-util/e-extensible.h>
+#include <e-util/e-marshal.h>
+#include <misc/e-interval-chooser.h>
+
+#include "e-source-config-backend.h"
+
+#define E_SOURCE_CONFIG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SOURCE_CONFIG, ESourceConfigPrivate))
+
+typedef struct _Candidate Candidate;
+
+struct _ESourceConfigPrivate {
+ ESource *original_source;
+ ESourceRegistry *registry;
+
+ GHashTable *backends;
+ GPtrArray *candidates;
+
+ GtkWidget *type_label;
+ GtkWidget *type_combo;
+ GtkWidget *name_entry;
+ GtkWidget *backend_box;
+ GtkSizeGroup *size_group;
+
+ gboolean complete;
+};
+
+struct _Candidate {
+ GtkWidget *page;
+ ESource *scratch_source;
+ ESourceConfigBackend *backend;
+};
+
+enum {
+ PROP_0,
+ PROP_COMPLETE,
+ PROP_ORIGINAL_SOURCE,
+ PROP_REGISTRY
+};
+
+enum {
+ CHECK_COMPLETE,
+ COMMIT_CHANGES,
+ INIT_CANDIDATE,
+ RESIZE_WINDOW,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE_WITH_CODE (
+ ESourceConfig,
+ e_source_config,
+ GTK_TYPE_BOX,
+ G_IMPLEMENT_INTERFACE (
+ E_TYPE_EXTENSIBLE, NULL))
+
+static void
+source_config_init_backends (ESourceConfig *config)
+{
+ GList *list, *iter;
+
+ config->priv->backends = g_hash_table_new_full (
+ (GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ e_extensible_load_extensions (E_EXTENSIBLE (config));
+
+ list = e_extensible_list_extensions (
+ E_EXTENSIBLE (config), E_TYPE_SOURCE_CONFIG_BACKEND);
+
+ for (iter = list; iter != NULL; iter = g_list_next (iter)) {
+ ESourceConfigBackend *backend;
+ ESourceConfigBackendClass *class;
+
+ backend = E_SOURCE_CONFIG_BACKEND (iter->data);
+ class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
+
+ if (class->backend_name != NULL)
+ g_hash_table_insert (
+ config->priv->backends,
+ g_strdup (class->backend_name),
+ g_object_ref (backend));
+ }
+
+ g_list_free (list);
+}
+
+static void
+source_config_add_candidate (ESourceConfig *config,
+ ESource *parent_source,
+ GFile *file)
+{
+ Candidate *candidate;
+ GtkBox *backend_box;
+ GtkComboBoxText *type_combo;
+ ESourceConfigBackend *backend;
+ const gchar *backend_name;
+ const gchar *display_name;
+ const gchar *parent_uid;
+
+ backend_box = GTK_BOX (config->priv->backend_box);
+ type_combo = GTK_COMBO_BOX_TEXT (config->priv->type_combo);
+
+ backend_name = e_source_get_backend_name (parent_source);
+ if (backend_name == NULL)
+ return;
+
+ backend = g_hash_table_lookup (config->priv->backends, backend_name);
+ if (!E_IS_SOURCE_CONFIG_BACKEND (backend))
+ return;
+
+ /* Some backends don't allow new sources to be created.
+ * The "contacts" calendar backend is one such example. */
+ if (file == NULL) {
+ if (!e_source_config_backend_allow_creation (backend))
+ return;
+ }
+
+ candidate = g_slice_new (Candidate);
+ candidate->backend = g_object_ref (backend);
+
+ /* Skip passing a GError here. If file is NULL, this should
+ * never fail. If file is non-NULL, it points to a key file
+ * which has already been successfully loaded so the chances
+ * of it failing to load this time are slim. */
+ candidate->scratch_source = e_source_new (file, NULL);
+
+ /* Do not show the page here. */
+ candidate->page = g_object_ref_sink (gtk_vbox_new (FALSE, 6));
+ gtk_box_pack_start (backend_box, candidate->page, FALSE, FALSE, 0);
+
+ parent_uid = e_source_get_uid (parent_source);
+ e_source_set_parent (candidate->scratch_source, parent_uid);
+
+ g_ptr_array_add (config->priv->candidates, candidate);
+
+ display_name = e_source_get_display_name (parent_source);
+ gtk_combo_box_text_append_text (type_combo, display_name);
+
+ /* Make sure the combo box has a valid active item before
+ * adding widgets. Otherwise we'll get run-time warnings
+ * as property bindings are set up. */
+ if (gtk_combo_box_get_active (GTK_COMBO_BOX (type_combo)) == -1)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (type_combo), 0);
+
+ g_signal_connect_swapped (
+ candidate->scratch_source, "changed",
+ G_CALLBACK (e_source_config_check_complete), config);
+
+ /* Bind the standard widgets to the new scratch source. */
+ g_signal_emit (
+ config, signals[INIT_CANDIDATE], 0,
+ candidate->scratch_source);
+
+ /* Insert any backend-specific widgets. */
+ e_source_config_backend_insert_widgets (
+ candidate->backend, candidate->scratch_source);
+}
+
+static void
+source_config_free_candidate (Candidate *candidate)
+{
+ g_object_unref (candidate->page);
+ g_object_unref (candidate->scratch_source);
+ g_object_unref (candidate->backend);
+
+ g_slice_free (Candidate, candidate);
+}
+
+static Candidate *
+source_config_get_active_candidate (ESourceConfig *config)
+{
+ GtkComboBox *type_combo;
+ gint index;
+
+ type_combo = GTK_COMBO_BOX (config->priv->type_combo);
+ index = gtk_combo_box_get_active (type_combo);
+ g_return_val_if_fail (index >= 0, NULL);
+
+ return g_ptr_array_index (config->priv->candidates, index);
+}
+
+static void
+source_config_type_combo_changed_cb (GtkComboBox *type_combo,
+ ESourceConfig *config)
+{
+ Candidate *candidate;
+ GPtrArray *array;
+ gint index;
+
+ array = config->priv->candidates;
+
+ for (index = 0; index < array->len; index++) {
+ candidate = g_ptr_array_index (array, index);
+ gtk_widget_hide (candidate->page);
+ }
+
+ index = gtk_combo_box_get_active (type_combo);
+ if (index == CLAMP (index, 0, array->len)) {
+ candidate = g_ptr_array_index (array, index);
+ gtk_widget_show (candidate->page);
+ }
+
+ e_source_config_resize_window (config);
+}
+
+static void
+source_config_set_original_source (ESourceConfig *config,
+ ESource *original_source)
+{
+ g_return_if_fail (config->priv->original_source == NULL);
+
+ if (original_source != NULL)
+ g_object_ref (original_source);
+
+ config->priv->original_source = original_source;
+}
+
+static void
+source_config_set_registry (ESourceConfig *config,
+ ESourceRegistry *registry)
+{
+ g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+ g_return_if_fail (config->priv->registry == NULL);
+
+ config->priv->registry = g_object_ref (registry);
+}
+
+static void
+source_config_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ORIGINAL_SOURCE:
+ source_config_set_original_source (
+ E_SOURCE_CONFIG (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_REGISTRY:
+ source_config_set_registry (
+ E_SOURCE_CONFIG (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_config_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_COMPLETE:
+ g_value_set_boolean (
+ value,
+ e_source_config_check_complete (
+ E_SOURCE_CONFIG (object)));
+ return;
+
+ case PROP_ORIGINAL_SOURCE:
+ g_value_set_object (
+ value,
+ e_source_config_get_original_source (
+ E_SOURCE_CONFIG (object)));
+ return;
+
+ case PROP_REGISTRY:
+ g_value_set_object (
+ value,
+ e_source_config_get_registry (
+ E_SOURCE_CONFIG (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_config_dispose (GObject *object)
+{
+ ESourceConfigPrivate *priv;
+
+ priv = E_SOURCE_CONFIG_GET_PRIVATE (object);
+
+ if (priv->original_source != NULL) {
+ g_object_unref (priv->original_source);
+ priv->original_source = NULL;
+ }
+
+ if (priv->registry != NULL) {
+ g_object_unref (priv->registry);
+ priv->registry = NULL;
+ }
+
+ if (priv->type_label != NULL) {
+ g_object_unref (priv->type_label);
+ priv->type_label = NULL;
+ }
+
+ if (priv->type_combo != NULL) {
+ g_object_unref (priv->type_combo);
+ priv->type_combo = NULL;
+ }
+
+ if (priv->name_entry != NULL) {
+ g_object_unref (priv->name_entry);
+ priv->name_entry = NULL;
+ }
+
+ if (priv->backend_box != NULL) {
+ g_object_unref (priv->backend_box);
+ priv->backend_box = NULL;
+ }
+
+ if (priv->size_group != NULL) {
+ g_object_unref (priv->size_group);
+ priv->size_group = NULL;
+ }
+
+ g_hash_table_remove_all (priv->backends);
+ g_ptr_array_set_size (priv->candidates, 0);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (e_source_config_parent_class)->dispose (object);
+}
+
+static void
+source_config_finalize (GObject *object)
+{
+ ESourceConfigPrivate *priv;
+
+ priv = E_SOURCE_CONFIG_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->backends);
+ g_ptr_array_free (priv->candidates, TRUE);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (e_source_config_parent_class)->finalize (object);
+}
+
+static void
+source_config_constructed (GObject *object)
+{
+ ESourceConfig *config;
+ ESource *original_source;
+
+ config = E_SOURCE_CONFIG (object);
+ original_source = e_source_config_get_original_source (config);
+
+ if (original_source != NULL)
+ e_source_config_insert_widget (
+ config, NULL, _("Type:"),
+ config->priv->type_label);
+ else
+ e_source_config_insert_widget (
+ config, NULL, _("Type:"),
+ config->priv->type_combo);
+
+ e_source_config_insert_widget (
+ config, NULL, _("Name:"),
+ config->priv->name_entry);
+
+ source_config_init_backends (config);
+}
+
+static void
+source_config_realize (GtkWidget *widget)
+{
+ ESourceConfig *config;
+ ESource *original_source;
+
+ /* Chain up to parent's realize() method. */
+ GTK_WIDGET_CLASS (e_source_config_parent_class)->realize (widget);
+
+ /* Do this after constructed() so subclasses can fully
+ * initialize themselves before we add candidates. */
+
+ config = E_SOURCE_CONFIG (widget);
+ original_source = e_source_config_get_original_source (config);
+
+ if (original_source != NULL) {
+ ESource *parent;
+ GFile *file;
+ GNode *node;
+ GtkLabel *type_label;
+ const gchar *display_name;
+ const gchar *uid;
+ gboolean sensitive;
+ GError *error = NULL;
+
+ /* Synchronize the original source to disk before cloning
+ * it in case the source was redirected to a non-existent
+ * file, such as for built-in sources like "system". */
+ if (!e_source_sync (original_source, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ file = e_source_get_file (original_source);
+ node = e_source_get_node (original_source);
+
+ g_return_if_fail (node->parent != NULL);
+ parent = E_SOURCE (node->parent->data);
+
+ type_label = GTK_LABEL (config->priv->type_label);
+ display_name = e_source_get_display_name (parent);
+ gtk_label_set_text (type_label, display_name);
+
+ /* The built-in "system" source cannot be renamed. */
+ uid = e_source_get_uid (original_source);
+ sensitive = (g_strcmp0 (uid, "system") != 0);
+ gtk_widget_set_sensitive (config->priv->name_entry, sensitive);
+
+ source_config_add_candidate (config, parent, file);
+
+ } else {
+ ESourceRegistry *registry;
+ GNode *tree, *child;
+
+ registry = e_source_config_get_registry (config);
+ tree = e_source_registry_build_display_tree (registry, NULL);
+ child = g_node_first_child (tree);
+
+ while (child != NULL) {
+ ESource *parent;
+
+ parent = E_SOURCE (child->data);
+ source_config_add_candidate (config, parent, NULL);
+ child = g_node_next_sibling (child);
+ }
+
+ g_node_destroy (tree);
+ }
+}
+
+static void
+source_config_init_candidate (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ g_object_bind_property (
+ scratch_source, "display-name",
+ config->priv->name_entry, "text",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
+
+static gboolean
+source_config_check_complete (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ GtkEntry *name_entry;
+ GtkComboBox *type_combo;
+ const gchar *text;
+
+ /* Make sure the Type: combo box has a valid item. */
+ type_combo = GTK_COMBO_BOX (config->priv->type_combo);
+ if (gtk_combo_box_get_active (type_combo) < 0)
+ return FALSE;
+
+ /* Make sure the Name: entry field is not empty. */
+ name_entry = GTK_ENTRY (config->priv->name_entry);
+ text = gtk_entry_get_text (name_entry);
+ if (text == NULL || *text == '\0')
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+source_config_commit_changes (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ /* FIXME Need error handling. Maybe implement EAlertSink? */
+ e_source_sync (scratch_source, NULL);
+}
+
+static void
+source_config_resize_window (ESourceConfig *config)
+{
+ GtkWidget *toplevel;
+
+ /* Expand or shrink our parent window vertically to accommodate
+ * the newly selected backend's options. Some backends have tons
+ * of options, some have few. This avoids the case where you
+ * select a backend with tons of options and then a backend with
+ * few options and wind up with lots of unused vertical space. */
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (config));
+
+ if (GTK_IS_WINDOW (toplevel)) {
+ GtkWindow *window = GTK_WINDOW (toplevel);
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (toplevel, &allocation);
+ gtk_window_resize (window, allocation.width, 1);
+ }
+}
+
+static gboolean
+source_config_check_complete_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer unused)
+{
+ gboolean v_boolean;
+
+ /* Abort emission if a handler returns FALSE. */
+ v_boolean = g_value_get_boolean (handler_return);
+ g_value_set_boolean (return_accu, v_boolean);
+
+ return v_boolean;
+}
+
+static void
+e_source_config_class_init (ESourceConfigClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ g_type_class_add_private (class, sizeof (ESourceConfigPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = source_config_set_property;
+ object_class->get_property = source_config_get_property;
+ object_class->dispose = source_config_dispose;
+ object_class->finalize = source_config_finalize;
+ object_class->constructed = source_config_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->realize = source_config_realize;
+
+ class->init_candidate = source_config_init_candidate;
+ class->check_complete = source_config_check_complete;
+ class->commit_changes = source_config_commit_changes;
+ class->resize_window = source_config_resize_window;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_COMPLETE,
+ g_param_spec_boolean (
+ "complete",
+ "Complete",
+ "Are the required fields complete?",
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ORIGINAL_SOURCE,
+ g_param_spec_object (
+ "original-source",
+ "Original Source",
+ "The original ESource",
+ E_TYPE_SOURCE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_REGISTRY,
+ g_param_spec_object (
+ "registry",
+ "Registry",
+ "Registry of ESources",
+ E_TYPE_SOURCE_REGISTRY,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ signals[CHECK_COMPLETE] = g_signal_new (
+ "check-complete",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ESourceConfigClass, check_complete),
+ source_config_check_complete_accumulator, NULL,
+ e_marshal_BOOLEAN__OBJECT,
+ G_TYPE_BOOLEAN, 1,
+ E_TYPE_SOURCE);
+
+ signals[COMMIT_CHANGES] = g_signal_new (
+ "commit-changes",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ESourceConfigClass, commit_changes),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_SOURCE);
+
+ signals[INIT_CANDIDATE] = g_signal_new (
+ "init-candidate",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ESourceConfigClass, init_candidate),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_SOURCE);
+
+ signals[RESIZE_WINDOW] = g_signal_new (
+ "resize-window",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ESourceConfigClass, resize_window),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+e_source_config_init (ESourceConfig *config)
+{
+ GPtrArray *candidates;
+ GtkSizeGroup *size_group;
+ PangoAttribute *attr;
+ PangoAttrList *attr_list;
+ GtkWidget *widget;
+
+ /* The candidates array holds scratch ESources, one for each
+ * item in the "type" combo box. Scratch ESources are never
+ * added to the registry, so backend extensions can make any
+ * changes they want to them. Whichever scratch ESource is
+ * "active" (selected in the "type" combo box) when the user
+ * clicks OK wins and is written to disk. The others are
+ * discarded. */
+ candidates = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) source_config_free_candidate);
+
+ /* The size group is used for caption labels. */
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ gtk_box_set_spacing (GTK_BOX (config), 6);
+
+ gtk_orientable_set_orientation (
+ GTK_ORIENTABLE (config), GTK_ORIENTATION_VERTICAL);
+
+ config->priv = E_SOURCE_CONFIG_GET_PRIVATE (config);
+ config->priv->candidates = candidates;
+ config->priv->size_group = size_group;
+
+ /* Either the combo box or the label is shown, never both.
+ * But we create both widgets and keep them both up-to-date
+ * regardless just because it makes the logic simpler. */
+
+ attr_list = pango_attr_list_new ();
+
+ attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+ pango_attr_list_insert (attr_list, attr);
+
+ widget = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
+ config->priv->type_label = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_combo_box_text_new ();
+ config->priv->type_combo = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_entry_new ();
+ gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+ config->priv->name_entry = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ /* The backend box holds backend-specific options. Each backend
+ * gets a child widget. Only one child widget is visible at once. */
+ widget = gtk_vbox_new (FALSE, 12);
+ gtk_box_pack_end (GTK_BOX (config), widget, TRUE, TRUE, 0);
+ config->priv->backend_box = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ pango_attr_list_unref (attr_list);
+
+ g_signal_connect (
+ config->priv->type_combo, "changed",
+ G_CALLBACK (source_config_type_combo_changed_cb), config);
+}
+
+GtkWidget *
+e_source_config_new (ESourceRegistry *registry,
+ ESource *original_source)
+{
+ g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+ if (original_source != NULL)
+ g_return_val_if_fail (E_IS_SOURCE (original_source), NULL);
+
+ return g_object_new (
+ E_TYPE_SOURCE_CONFIG, "registry", registry,
+ "original-source", original_source, NULL);
+}
+
+void
+e_source_config_insert_widget (ESourceConfig *config,
+ ESource *scratch_source,
+ const gchar *caption,
+ GtkWidget *widget)
+{
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *label;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG (config));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ if (scratch_source == NULL)
+ vbox = GTK_WIDGET (config);
+ else
+ vbox = e_source_config_get_page (config, scratch_source);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+
+ g_object_bind_property (
+ widget, "visible",
+ hbox, "visible",
+ G_BINDING_SYNC_CREATE);
+
+ label = gtk_label_new (caption);
+ gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+ gtk_size_group_add_widget (config->priv->size_group, label);
+ gtk_widget_show (label);
+
+ gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+}
+
+GtkWidget *
+e_source_config_get_page (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ Candidate *candidate;
+ GtkWidget *page = NULL;
+ GPtrArray *array;
+ gint index;
+
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
+ g_return_val_if_fail (E_IS_SOURCE (scratch_source), NULL);
+
+ array = config->priv->candidates;
+
+ for (index = 0; page == NULL && index < array->len; index++) {
+ candidate = g_ptr_array_index (array, index);
+ if (e_source_equal (scratch_source, candidate->scratch_source))
+ page = candidate->page;
+ }
+
+ g_return_val_if_fail (GTK_IS_BOX (page), NULL);
+
+ return page;
+}
+
+gboolean
+e_source_config_check_complete (ESourceConfig *config)
+{
+ Candidate *candidate;
+ gboolean complete;
+
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), FALSE);
+
+ candidate = source_config_get_active_candidate (config);
+ g_return_val_if_fail (candidate != NULL, FALSE);
+
+ g_signal_emit (
+ config, signals[CHECK_COMPLETE], 0,
+ candidate->scratch_source, &complete);
+
+ complete &= e_source_config_backend_check_complete (
+ candidate->backend, candidate->scratch_source);
+
+ /* XXX Emitting "notify::complete" may cause this function
+ * to be called repeatedly by signal handlers. The IF
+ * check below should break any recursive cycles. Not
+ * very efficient but I think we can live with it. */
+
+ if (complete != config->priv->complete) {
+ config->priv->complete = complete;
+ g_object_notify (G_OBJECT (config), "complete");
+ }
+
+ return complete;
+}
+
+void
+e_source_config_commit_changes (ESourceConfig *config)
+{
+ Candidate *candidate;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG (config));
+
+ candidate = source_config_get_active_candidate (config);
+ g_return_if_fail (candidate != NULL);
+
+ e_source_config_backend_commit_changes (
+ candidate->backend, candidate->scratch_source);
+
+ g_signal_emit (
+ config, signals[COMMIT_CHANGES], 0,
+ candidate->scratch_source);
+}
+
+ESource *
+e_source_config_get_original_source (ESourceConfig *config)
+{
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
+
+ return config->priv->original_source;
+}
+
+ESourceRegistry *
+e_source_config_get_registry (ESourceConfig *config)
+{
+ g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
+
+ return config->priv->registry;
+}
+
+void
+e_source_config_resize_window (ESourceConfig *config)
+{
+ g_return_if_fail (E_IS_SOURCE_CONFIG (config));
+
+ g_signal_emit (config, signals[RESIZE_WINDOW], 0);
+}
+
+void
+e_source_config_add_refresh_interval (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ GtkWidget *widget;
+ GtkWidget *container;
+ ESourceExtension *extension;
+ const gchar *extension_name;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG (config));
+ g_return_if_fail (E_IS_SOURCE (scratch_source));
+
+ extension_name = E_SOURCE_EXTENSION_REFRESH;
+ extension = e_source_get_extension (scratch_source, extension_name);
+
+ widget = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
+ e_source_config_insert_widget (config, scratch_source, NULL, widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_hbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ /* Translators: This is the first of a sequence of widgets:
+ * "Refresh every [NUMERIC_ENTRY] [TIME_UNITS_COMBO]" */
+ widget = gtk_label_new (_("Refresh every"));
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ widget = e_interval_chooser_new ();
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ extension, "interval-minutes",
+ widget, "interval-minutes",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
+
+void
+e_source_config_add_secure_connection (ESourceConfig *config,
+ ESource *scratch_source)
+{
+ GtkWidget *widget;
+ ESourceExtension *extension;
+ const gchar *extension_name;
+ const gchar *label;
+
+ g_return_if_fail (E_IS_SOURCE_CONFIG (config));
+ g_return_if_fail (E_IS_SOURCE (scratch_source));
+
+ extension_name = E_SOURCE_EXTENSION_SECURITY;
+ extension = e_source_get_extension (scratch_source, extension_name);
+
+ label = _("Use a secure connection");
+ widget = gtk_check_button_new_with_label (label);
+ e_source_config_insert_widget (config, scratch_source, NULL, widget);
+ gtk_widget_show (widget);
+
+ g_object_bind_property (
+ extension, "secure",
+ widget, "active",
+ G_BINDING_BIDIRECTIONAL |
+ G_BINDING_SYNC_CREATE);
+}
diff --git a/widgets/misc/e-source-config.h b/widgets/misc/e-source-config.h
new file mode 100644
index 0000000..d194b0c
--- /dev/null
+++ b/widgets/misc/e-source-config.h
@@ -0,0 +1,93 @@
+/*
+ * e-source-config.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_SOURCE_CONFIG_H
+#define E_SOURCE_CONFIG_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-source-registry.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CONFIG \
+ (e_source_config_get_type ())
+#define E_SOURCE_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SOURCE_CONFIG, ESourceConfig))
+#define E_SOURCE_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SOURCE_CONFIG, ESourceConfigClass))
+#define E_IS_SOURCE_CONFIG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SOURCE_CONFIG))
+#define E_IS_SOURCE_CONFIG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SOURCE_CONFIG))
+#define E_SOURCE_CONFIG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SOURCE_CONFIG, ESourceConfigClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceConfig ESourceConfig;
+typedef struct _ESourceConfigClass ESourceConfigClass;
+typedef struct _ESourceConfigPrivate ESourceConfigPrivate;
+
+struct _ESourceConfig {
+ GtkBox parent;
+ ESourceConfigPrivate *priv;
+};
+
+struct _ESourceConfigClass {
+ GtkBoxClass parent_class;
+
+ /* Signals */
+ void (*init_candidate) (ESourceConfig *config,
+ ESource *scratch_source);
+ gboolean (*check_complete) (ESourceConfig *config,
+ ESource *scratch_source);
+ void (*commit_changes) (ESourceConfig *config,
+ ESource *scratch_source);
+ void (*resize_window) (ESourceConfig *config);
+};
+
+GType e_source_config_get_type (void) G_GNUC_CONST;
+GtkWidget * e_source_config_new (ESourceRegistry *registry,
+ ESource *original_source);
+void e_source_config_insert_widget (ESourceConfig *config,
+ ESource *scratch_source,
+ const gchar *caption,
+ GtkWidget *widget);
+GtkWidget * e_source_config_get_page (ESourceConfig *config,
+ ESource *scratch_source);
+gboolean e_source_config_check_complete (ESourceConfig *config);
+void e_source_config_commit_changes (ESourceConfig *config);
+ESource * e_source_config_get_original_source
+ (ESourceConfig *config);
+ESourceRegistry *
+ e_source_config_get_registry (ESourceConfig *config);
+void e_source_config_resize_window (ESourceConfig *config);
+
+/* Convenience functions for common settings. */
+void e_source_config_add_refresh_interval
+ (ESourceConfig *config,
+ ESource *scratch_source);
+void e_source_config_add_secure_connection
+ (ESourceConfig *config,
+ ESource *scratch_source);
+
+#endif /* E_SOURCE_CONFIG_H */
diff --git a/widgets/misc/test-source-config.c b/widgets/misc/test-source-config.c
new file mode 100644
index 0000000..5c98d26
--- /dev/null
+++ b/widgets/misc/test-source-config.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <libebook/e-source-address-book.h>
+
+#include "e-source-config-dialog.h"
+
+static void
+dialog_response (GtkDialog *dialog,
+ gint response_id)
+{
+ gtk_main_quit ();
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+ ESourceRegistry *registry;
+ ESource *source = NULL;
+ GtkWidget *config;
+ GtkWidget *dialog;
+ GError *error = NULL;
+
+ gtk_init (&argc, &argv);
+
+ if (argc > 1) {
+ GFile *file;
+
+ file = g_file_new_for_commandline_arg (argv[1]);
+ source = e_source_new (file, &error);
+ g_object_unref (file);
+
+ if (error != NULL) {
+ g_printerr ("%s\n", error->message);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ E_TYPE_SOURCE_ADDRESS_BOOK;
+
+ registry = e_source_registry_get_default ();
+
+ if (!e_source_registry_load_sources (registry, &error)) {
+ g_printerr ("%s\n", error->message);
+ exit (EXIT_FAILURE);
+ }
+
+ config = e_source_config_new (registry, source);
+ dialog = e_source_config_dialog_new (E_SOURCE_CONFIG (config), NULL);
+
+ g_signal_connect (
+ dialog, "response",
+ G_CALLBACK (dialog_response), NULL);
+
+ gtk_widget_show (config);
+ gtk_widget_show (dialog);
+
+ gtk_main ();
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]