diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2012-12-10 21:09:59 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2012-12-13 03:33:43 +0800 |
commit | d09d8de870b6697c8a8b262e7e077b871a69b315 (patch) | |
tree | 3b718882e7a0bb0a996daf2967a033d91714c9b5 /widgets/misc/e-source-config.c | |
parent | b61331ed03ac1c7a9b8614e25510040b9c60ae02 (diff) | |
download | gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.gz gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.bz2 gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.lz gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.xz gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.tar.zst gsoc2013-evolution-d09d8de870b6697c8a8b262e7e077b871a69b315.zip |
Consolidate base utility libraries into libeutil.
Evolution consists of entirely too many small utility libraries, which
increases linking and loading time, places a burden on higher layers of
the application (e.g. modules) which has to remember to link to all the
small in-tree utility libraries, and makes it difficult to generate API
documentation for these utility libraries in one Gtk-Doc module.
Merge the following utility libraries under the umbrella of libeutil,
and enforce a single-include policy on libeutil so we can reorganize
the files as desired without disrupting its pseudo-public API.
libemail-utils/libemail-utils.la
libevolution-utils/libevolution-utils.la
filter/libfilter.la
widgets/e-timezone-dialog/libetimezonedialog.la
widgets/menus/libmenus.la
widgets/misc/libemiscwidgets.la
widgets/table/libetable.la
widgets/text/libetext.la
This also merges libedataserverui from the Evolution-Data-Server module,
since Evolution is its only consumer nowadays, and I'd like to make some
improvements to those APIs without concern for backward-compatibility.
And finally, start a Gtk-Doc module for libeutil. It's going to be a
project just getting all the symbols _listed_ much less _documented_.
But the skeletal structure is in place and I'm off to a good start.
Diffstat (limited to 'widgets/misc/e-source-config.c')
-rw-r--r-- | widgets/misc/e-source-config.c | 1448 |
1 files changed, 0 insertions, 1448 deletions
diff --git a/widgets/misc/e-source-config.c b/widgets/misc/e-source-config.c deleted file mode 100644 index f5ef35287c..0000000000 --- a/widgets/misc/e-source-config.c +++ /dev/null @@ -1,1448 +0,0 @@ -/* - * 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 <libebackend/libebackend.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; - ESource *collection_source; - ESourceRegistry *registry; - - GHashTable *backends; - GPtrArray *candidates; - - GtkWidget *type_label; - GtkWidget *type_combo; - GtkWidget *name_label; - GtkWidget *name_entry; - GtkWidget *backend_box; - GtkSizeGroup *size_group; - - gboolean complete; -}; - -struct _Candidate { - GtkWidget *page; - ESource *scratch_source; - ESourceConfigBackend *backend; - gulong changed_handler_id; -}; - -enum { - PROP_0, - PROP_COLLECTION_SOURCE, - 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 gint -source_config_compare_sources (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - ESource *source_a; - ESource *source_b; - ESource *parent_a; - ESource *parent_b; - ESourceConfig *config; - ESourceRegistry *registry; - const gchar *parent_uid_a; - const gchar *parent_uid_b; - gint result; - - source_a = E_SOURCE (a); - source_b = E_SOURCE (b); - config = E_SOURCE_CONFIG (user_data); - - if (e_source_equal (source_a, source_b)) - return 0; - - /* "On This Computer" always comes first. */ - - parent_uid_a = e_source_get_parent (source_a); - parent_uid_b = e_source_get_parent (source_b); - - if (g_strcmp0 (parent_uid_a, "local-stub") == 0) - return -1; - - if (g_strcmp0 (parent_uid_b, "local-stub") == 0) - return 1; - - registry = e_source_config_get_registry (config); - - parent_a = e_source_registry_ref_source (registry, parent_uid_a); - parent_b = e_source_registry_ref_source (registry, parent_uid_b); - - g_return_val_if_fail (parent_a != NULL, 1); - g_return_val_if_fail (parent_b != NULL, -1); - - result = e_source_compare_by_display_name (parent_a, parent_b); - - g_object_unref (parent_a); - g_object_unref (parent_b); - - return result; -} - -static void -source_config_add_candidate (ESourceConfig *config, - ESource *scratch_source, - ESourceConfigBackend *backend) -{ - Candidate *candidate; - GtkBox *backend_box; - GtkLabel *type_label; - GtkComboBoxText *type_combo; - ESource *parent_source; - ESourceRegistry *registry; - const gchar *display_name; - const gchar *parent_uid; - gulong handler_id; - - backend_box = GTK_BOX (config->priv->backend_box); - type_label = GTK_LABEL (config->priv->type_label); - type_combo = GTK_COMBO_BOX_TEXT (config->priv->type_combo); - - registry = e_source_config_get_registry (config); - parent_uid = e_source_get_parent (scratch_source); - parent_source = e_source_registry_ref_source (registry, parent_uid); - g_return_if_fail (parent_source != NULL); - - candidate = g_slice_new (Candidate); - candidate->backend = g_object_ref (backend); - candidate->scratch_source = g_object_ref (scratch_source); - - /* 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); - - 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); - gtk_label_set_text (type_label, 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); - - /* 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); - - handler_id = g_signal_connect_swapped ( - candidate->scratch_source, "changed", - G_CALLBACK (e_source_config_check_complete), config); - - candidate->changed_handler_id = handler_id; - - /* Trigger the "changed" handler we just connected to set the - * initial "complete" state based on the widgets we just added. */ - e_source_changed (candidate->scratch_source); - - g_object_unref (parent_source); -} - -static void -source_config_free_candidate (Candidate *candidate) -{ - g_signal_handler_disconnect ( - candidate->scratch_source, - candidate->changed_handler_id); - - 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); - e_source_config_check_complete (config); -} - -static gboolean -source_config_init_for_adding_source_foreach (gpointer key, - gpointer value, - gpointer user_data) -{ - ESource *scratch_source; - ESourceBackend *extension; - ESourceConfig *config; - ESourceConfigBackend *backend; - ESourceConfigBackendClass *class; - const gchar *extension_name; - - scratch_source = E_SOURCE (key); - backend = E_SOURCE_CONFIG_BACKEND (value); - config = E_SOURCE_CONFIG (user_data); - - /* This may not be the correct backend name for the child of a - * collection. For example, the "yahoo" collection backend uses - * the "caldav" calender backend for calendar children. But the - * ESourceCollectionBackend can override our setting if needed. */ - class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend); - extension_name = e_source_config_get_backend_extension_name (config); - extension = e_source_get_extension (scratch_source, extension_name); - e_source_backend_set_backend_name (extension, class->backend_name); - - source_config_add_candidate (config, scratch_source, backend); - - return FALSE; /* don't stop traversal */ -} - -static void -source_config_init_for_adding_source (ESourceConfig *config) -{ - GList *list, *link; - ESourceRegistry *registry; - GTree *scratch_source_tree; - - /* Candidates are drawn from two sources: - * - * ESourceConfigBackend classes that specify a fixed parent UID, - * meaning there exists one only possible parent source for any - * scratch source created by the backend. The fixed parent UID - * should be a built-in "stub" placeholder ("local-stub", etc). - * - * -and- - * - * Collection sources. We let ESourceConfig subclasses gather - * eligible collection sources to serve as parents for scratch - * sources. A scratch source is matched to a backend based on - * the collection's backend name. The "calendar-enabled" and - * "contacts-enabled" settings also factor into eligibility. - */ - - /* Use a GTree instead of a GHashTable so inserted scratch - * sources automatically sort themselves by their parent's - * display name. */ - scratch_source_tree = g_tree_new_full ( - source_config_compare_sources, config, - (GDestroyNotify) g_object_unref, - (GDestroyNotify) g_object_unref); - - registry = e_source_config_get_registry (config); - - /* First pick out the backends with a fixed parent UID. */ - - list = g_hash_table_get_values (config->priv->backends); - - for (link = list; link != NULL; link = g_list_next (link)) { - ESourceConfigBackend *backend; - ESourceConfigBackendClass *class; - ESource *scratch_source; - ESource *parent_source; - gboolean parent_is_disabled; - - backend = E_SOURCE_CONFIG_BACKEND (link->data); - class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend); - - if (class->parent_uid == NULL) - continue; - - /* Verify the fixed parent UID is valid. */ - parent_source = e_source_registry_ref_source ( - registry, class->parent_uid); - if (parent_source == NULL) { - g_warning ( - "%s: %sClass specifies " - "an invalid parent_uid '%s'", - G_STRFUNC, - G_OBJECT_TYPE_NAME (backend), - class->parent_uid); - continue; - } - parent_is_disabled = !e_source_get_enabled (parent_source); - g_object_unref (parent_source); - - /* It's unusual for a fixed parent source to be disabled. - * A user would have to go out of his way to do this, but - * we should honor it regardless. */ - if (parent_is_disabled) - continue; - - /* Some backends don't allow new sources to be created. - * The "contacts" calendar backend is one such example. */ - if (!e_source_config_backend_allow_creation (backend)) - continue; - - scratch_source = e_source_new (NULL, NULL, NULL); - g_return_if_fail (scratch_source != NULL); - - e_source_set_parent (scratch_source, class->parent_uid); - - g_tree_insert ( - scratch_source_tree, - g_object_ref (scratch_source), - g_object_ref (backend)); - - g_object_unref (scratch_source); - } - - g_list_free (list); - - /* Next gather eligible collection sources to serve as parents. */ - - list = e_source_config_list_eligible_collections (config); - - for (link = list; link != NULL; link = g_list_next (link)) { - ESource *parent_source; - ESource *scratch_source; - ESourceBackend *extension; - ESourceConfigBackend *backend = NULL; - const gchar *backend_name; - const gchar *parent_uid; - - parent_source = E_SOURCE (link->data); - parent_uid = e_source_get_uid (parent_source); - - extension = e_source_get_extension ( - parent_source, E_SOURCE_EXTENSION_COLLECTION); - backend_name = e_source_backend_get_backend_name (extension); - - if (backend_name != NULL) - backend = g_hash_table_lookup ( - config->priv->backends, backend_name); - - if (backend == NULL) - continue; - - /* Some backends disallow creating certain types of - * resources. For example, the Exchange Web Services - * backend disallows creating new memo lists. */ - if (!e_source_config_backend_allow_creation (backend)) - continue; - - scratch_source = e_source_new (NULL, NULL, NULL); - g_return_if_fail (scratch_source != NULL); - - e_source_set_parent (scratch_source, parent_uid); - - g_tree_insert ( - scratch_source_tree, - g_object_ref (scratch_source), - g_object_ref (backend)); - - g_object_unref (scratch_source); - } - - g_list_free_full (list, (GDestroyNotify) g_object_unref); - - /* XXX GTree doesn't get as much love as GHashTable. - * It's missing an equivalent to GHashTableIter. */ - g_tree_foreach ( - scratch_source_tree, - source_config_init_for_adding_source_foreach, config); - - g_tree_unref (scratch_source_tree); -} - -static void -source_config_init_for_editing_source (ESourceConfig *config) -{ - ESource *original_source; - ESource *scratch_source; - ESourceBackend *extension; - ESourceConfigBackend *backend; - GDBusObject *dbus_object; - const gchar *backend_name; - const gchar *extension_name; - - original_source = e_source_config_get_original_source (config); - g_return_if_fail (original_source != NULL); - - extension_name = e_source_config_get_backend_extension_name (config); - extension = e_source_get_extension (original_source, extension_name); - backend_name = e_source_backend_get_backend_name (extension); - g_return_if_fail (backend_name != NULL); - - backend = g_hash_table_lookup (config->priv->backends, backend_name); - g_return_if_fail (backend != NULL); - - dbus_object = e_source_ref_dbus_object (original_source); - g_return_if_fail (dbus_object != NULL); - - scratch_source = e_source_new (dbus_object, NULL, NULL); - g_return_if_fail (scratch_source != NULL); - - source_config_add_candidate (config, scratch_source, backend); - - g_object_unref (scratch_source); - g_object_unref (dbus_object); -} - -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_COLLECTION_SOURCE: - g_value_set_object ( - value, - e_source_config_get_collection_source ( - E_SOURCE_CONFIG (object))); - return; - - 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->collection_source != NULL) { - g_object_unref (priv->collection_source); - priv->collection_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_label != NULL) { - g_object_unref (priv->name_label); - priv->name_label = 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; - ESourceRegistry *registry; - ESource *original_source; - ESource *collection_source = NULL; - - config = E_SOURCE_CONFIG (object); - registry = e_source_config_get_registry (config); - original_source = e_source_config_get_original_source (config); - - /* If we have an original source, see if it's part - * of a collection and note the collection source. */ - if (original_source != NULL) { - const gchar *extension_name; - - extension_name = E_SOURCE_EXTENSION_COLLECTION; - collection_source = e_source_registry_find_extension ( - registry, original_source, extension_name); - config->priv->collection_source = collection_source; - } - - 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); - - /* If the original source is part of a collection then we assume - * the display name is server-assigned and not user-assigned, at - * least not assigned through Evolution. */ - if (collection_source != NULL) - e_source_config_insert_widget ( - config, NULL, _("Name:"), - config->priv->name_label); - else - 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) - source_config_init_for_adding_source (config); - else - source_config_init_for_editing_source (config); -} - -static GList * -source_config_list_eligible_collections (ESourceConfig *config) -{ - ESourceRegistry *registry; - GQueue trash = G_QUEUE_INIT; - GList *list, *link; - const gchar *extension_name; - - extension_name = E_SOURCE_EXTENSION_COLLECTION; - registry = e_source_config_get_registry (config); - - list = e_source_registry_list_sources (registry, extension_name); - - for (link = list; link != NULL; link = g_list_next (link)) { - ESource *source = E_SOURCE (link->data); - gboolean elligible; - - elligible = - e_source_get_enabled (source) && - e_source_get_remote_creatable (source); - - if (!elligible) - g_queue_push_tail (&trash, link); - } - - /* Remove ineligible collections from the list. */ - while ((link = g_queue_pop_head (&trash)) != NULL) { - g_object_unref (link->data); - list = g_list_delete_link (list, link); - } - - return list; -} - -static void -source_config_init_candidate (ESourceConfig *config, - ESource *scratch_source) -{ - g_object_bind_property ( - scratch_source, "display-name", - config->priv->name_label, "label", - G_BINDING_SYNC_CREATE); - - 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) -{ - /* Placeholder so subclasses can safely chain up. */ -} - -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->list_eligible_collections = - source_config_list_eligible_collections; - 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_COLLECTION_SOURCE, - g_param_spec_object ( - "collection-source", - "Collection Source", - "The collection ESource to which " - "the ESource being edited belongs", - E_TYPE_SOURCE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - 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; - - attr_list = pango_attr_list_new (); - - attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); - pango_attr_list_insert (attr_list, attr); - - /* Either the source type combo box or the label is shown, - * never both. But we create both widgets and keep them - * both up-to-date because it makes the logic simpler. */ - - 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); - - /* Similarly for the display name. Either the text entry - * or the label is shown, depending on whether the source - * is a collection member (new sources never are). */ - - 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->name_label = 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; -} - -const gchar * -e_source_config_get_backend_extension_name (ESourceConfig *config) -{ - ESourceConfigClass *class; - - g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL); - - class = E_SOURCE_CONFIG_GET_CLASS (config); - g_return_val_if_fail (class->get_backend_extension_name != NULL, NULL); - - return class->get_backend_extension_name (config); -} - -GList * -e_source_config_list_eligible_collections (ESourceConfig *config) -{ - ESourceConfigClass *class; - - g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL); - - class = E_SOURCE_CONFIG_GET_CLASS (config); - g_return_val_if_fail (class->list_eligible_collections != NULL, NULL); - - return class->list_eligible_collections (config); -} - -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; -} - -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; -} - -ESource * -e_source_config_get_collection_source (ESourceConfig *config) -{ - g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL); - - return config->priv->collection_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); -} - -/* Helper for e_source_config_commit() */ -static void -source_config_commit_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - GError *error = NULL; - - simple = G_SIMPLE_ASYNC_RESULT (user_data); - - e_source_registry_commit_source_finish ( - E_SOURCE_REGISTRY (object), result, &error); - - if (error != NULL) - g_simple_async_result_take_error (simple, error); - - g_simple_async_result_complete (simple); - g_object_unref (simple); -} - -void -e_source_config_commit (ESourceConfig *config, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *simple; - ESourceRegistry *registry; - Candidate *candidate; - - g_return_if_fail (E_IS_SOURCE_CONFIG (config)); - - registry = e_source_config_get_registry (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); - - simple = g_simple_async_result_new ( - G_OBJECT (config), callback, - user_data, e_source_config_commit); - - e_source_registry_commit_source ( - registry, candidate->scratch_source, - cancellable, source_config_commit_cb, simple); -} - -gboolean -e_source_config_commit_finish (ESourceConfig *config, - GAsyncResult *result, - GError **error) -{ - GSimpleAsyncResult *simple; - - g_return_val_if_fail ( - g_simple_async_result_is_valid ( - result, G_OBJECT (config), - e_source_config_commit), FALSE); - - simple = G_SIMPLE_ASYNC_RESULT (result); - - /* Assume success unless a GError is set. */ - return !g_simple_async_result_propagate_error (simple, error); -} - -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); -} - -static gboolean -secure_to_port_cb (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - GObject *authentication_extension; - guint16 port; - - authentication_extension = g_binding_get_target (binding); - g_object_get (authentication_extension, "port", &port, NULL); - - if (port == 80 || port == 443 || port == 0) - port = g_value_get_boolean (source_value) ? 443 : 80; - - g_value_set_uint (target_value, port); - - return TRUE; -} - -void -e_source_config_add_secure_connection_for_webdav (ESourceConfig *config, - ESource *scratch_source) -{ - GtkWidget *widget1; - GtkWidget *widget2; - ESourceExtension *extension; - ESourceAuthentication *authentication_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"); - widget1 = gtk_check_button_new_with_label (label); - e_source_config_insert_widget (config, scratch_source, NULL, widget1); - gtk_widget_show (widget1); - - g_object_bind_property ( - extension, "secure", - widget1, "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; - authentication_extension = e_source_get_extension (scratch_source, extension_name); - - g_object_bind_property_full ( - extension, "secure", - authentication_extension, "port", - G_BINDING_DEFAULT, - secure_to_port_cb, - NULL, NULL, NULL); - - extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND; - extension = e_source_get_extension (scratch_source, extension_name); - - label = _("Ignore invalid SSL certificate"); - widget2 = gtk_check_button_new_with_label (label); - gtk_widget_set_margin_left (widget2, 24); - e_source_config_insert_widget (config, scratch_source, NULL, widget2); - gtk_widget_show (widget2); - - g_object_bind_property ( - widget1, "active", - widget2, "sensitive", - G_BINDING_SYNC_CREATE); - - g_object_bind_property ( - extension, "ignore-invalid-cert", - widget2, "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); -} - -void -e_source_config_add_user_entry (ESourceConfig *config, - ESource *scratch_source) -{ - GtkWidget *widget; - ESource *original_source; - 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_AUTHENTICATION; - extension = e_source_get_extension (scratch_source, extension_name); - - original_source = e_source_config_get_original_source (config); - - widget = gtk_entry_new (); - e_source_config_insert_widget ( - config, scratch_source, _("User"), widget); - gtk_widget_show (widget); - - g_object_bind_property ( - extension, "user", - widget, "text", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - /* If this is a new data source, initialize the - * GtkEntry to the user name of the current user. */ - if (original_source == NULL) - gtk_entry_set_text (GTK_ENTRY (widget), g_get_user_name ()); -} - |