From 4bca50f1c5060efbfe2f0c9d011e4d51f1e8be0f Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 28 Nov 2007 20:54:19 +0000 Subject: ** Fixes bug #489652 2007-11-28 Matthew Barnes ** Fixes bug #489652 Migrate the contact list editor from ETable to GtkTreeView and fix some HIG issues. * addressbook/gui/contact-list-editor/Makefile.am: Remove e-contact-list-editor.etspec Remove e-contact-list-editor-marshal.list * addressbook/gui/contact-list-editor/contact-list-editor.glade: Fix some HIG issues and give all the widgets proper names. * addressbook/gui/contact-list-editor/e-contact-list-model.c: * addressbook/gui/contact-list-editor/e-contact-list-model.h: EContactListModel is now a subclass of GtkListStore. * addressbook/gui/contact-list-editor/e-contact-list.c: * addressbook/gui/contact-list-editor/e-contact-list.h: Use a GtkTreeView instead of an ETable for displaying members. Refactor everything; see bug #489652 for more details. svn path=/trunk/; revision=34610 --- .../contact-list-editor/e-contact-list-editor.c | 2063 +++++++++++--------- 1 file changed, 1158 insertions(+), 905 deletions(-) (limited to 'addressbook/gui/contact-list-editor/e-contact-list-editor.c') diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.c b/addressbook/gui/contact-list-editor/e-contact-list-editor.c index 85a7b507d5..a40be485da 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor.c +++ b/addressbook/gui/contact-list-editor/e-contact-list-editor.c @@ -21,27 +21,19 @@ #include #include "e-contact-list-editor.h" -#include #include #include #include +#include #include -#include -#include -#include -#include +#include #include -#include -#include - #include "shell/evolution-shell-component-utils.h" -#include "misc/e-image-chooser.h" - #include "addressbook/gui/component/addressbook.h" #include "addressbook/gui/widgets/eab-gui-util.h" #include "addressbook/util/eab-book-util.h" @@ -49,66 +41,43 @@ #include "eab-editor.h" #include "e-contact-editor.h" #include "e-contact-list-model.h" -#include "e-contact-list-editor-marshal.h" #include "eab-contact-merging.h" -#include - -static void e_contact_list_editor_init (EContactListEditor *editor); -static void e_contact_list_editor_class_init (EContactListEditorClass *klass); -static void e_contact_list_editor_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void e_contact_list_editor_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void e_contact_list_editor_dispose (GObject *object); - -static void e_contact_list_editor_show (EABEditor *editor); -static void e_contact_list_editor_raise (EABEditor *editor); -static void e_contact_list_editor_close (EABEditor *editor); -static void e_contact_list_editor_save_contact (EABEditor *editor, gboolean should_close); -static gboolean e_contact_list_editor_is_valid (EABEditor *editor); -static gboolean e_contact_list_editor_is_changed (EABEditor *editor); -static GtkWindow* e_contact_list_editor_get_window (EABEditor *editor); - -static void set_editable (EContactListEditor *editor); -static void command_state_changed (EContactListEditor *editor); -static void extract_info(EContactListEditor *editor); -static void fill_in_info(EContactListEditor *editor); - -static void add_email_cb (GtkWidget *w, EContactListEditor *editor); -static void remove_entry_cb (GtkWidget *w, EContactListEditor *editor); -static void select_cb (GtkWidget *w, EContactListEditor *editor); -static void list_name_changed_cb (GtkWidget *w, EContactListEditor *editor); -static void list_image_changed_cb (GtkWidget *w, EContactListEditor *editor); -static void visible_addrs_toggled_cb (GtkWidget *w, EContactListEditor *editor); -static void source_changed_cb (ESourceComboBox *source_combo_box, EContactListEditor *editor); -static gboolean email_key_pressed (GtkWidget *w, GdkEventKey *event, EContactListEditor *editor); -static void email_match_selected (GtkWidget *w, EDestination *destination, EContactListEditor *editor); - -static void close_cb (GtkWidget *widget, EContactListEditor *editor); -static void save_and_close_cb (GtkWidget *widget, EContactListEditor *editor); - -static gint app_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data); -static gboolean table_drag_drop_cb (ETable *table, int row, int col, GdkDragContext *context, - gint x, gint y, guint time, EContactListEditor *editor); -static gboolean table_drag_motion_cb (ETable *table, int row, int col, GdkDragContext *context, - gint x, gint y, guint time, EContactListEditor *editor); -static void table_drag_data_received_cb (ETable *table, int row, int col, - GdkDragContext *context, - gint x, gint y, - GtkSelectionData *selection_data, guint info, guint time, - EContactListEditor *editor); - -static EABEditorClass *parent_class = NULL; - -enum DndTargetType { - DND_TARGET_TYPE_VCARD, -}; -#define VCARD_TYPE "text/x-vcard" -static GtkTargetEntry list_drag_types[] = { - { VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD }, -}; -static const int num_list_drag_types = sizeof (list_drag_types) / sizeof (list_drag_types[0]); +#define E_CONTACT_LIST_EDITOR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditorPrivate)) + +#define CONTACT_LIST_EDITOR_WIDGET(editor, name) \ + (glade_xml_get_widget \ + (E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor)->xml, name)) + +/* More macros, less typos. */ +#define CONTACT_LIST_EDITOR_WIDGET_ADD_BUTTON(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "add-button") +#define CONTACT_LIST_EDITOR_WIDGET_CHECK_BUTTON(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "check-button") +#define CONTACT_LIST_EDITOR_WIDGET_DIALOG(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "dialog") +#define CONTACT_LIST_EDITOR_WIDGET_EMAIL_ENTRY(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "email-entry") +#define CONTACT_LIST_EDITOR_WIDGET_LIST_NAME_ENTRY(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "list-name-entry") +#define CONTACT_LIST_EDITOR_WIDGET_MEMBERS_VBOX(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "members-vbox") +#define CONTACT_LIST_EDITOR_WIDGET_OK_BUTTON(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "ok-button") +#define CONTACT_LIST_EDITOR_WIDGET_REMOVE_BUTTON(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "remove-button") +#define CONTACT_LIST_EDITOR_WIDGET_SOURCE_MENU(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "source-combo-box") +#define CONTACT_LIST_EDITOR_WIDGET_TREE_VIEW(editor) \ + CONTACT_LIST_EDITOR_WIDGET ((editor), "tree-view") + +/* Shorthand, requires a variable named "editor". */ +#define WIDGET(name) (CONTACT_LIST_EDITOR_WIDGET_##name (editor)) + +#define TOPLEVEL_KEY (g_type_name (E_TYPE_CONTACT_LIST_EDITOR)) -/* The arguments we take */ enum { PROP_0, PROP_BOOK, @@ -117,1160 +86,1444 @@ enum { PROP_EDITABLE }; -GType -e_contact_list_editor_get_type (void) -{ - static GType cle_type = 0; +typedef struct { + EContactListEditor *editor; + gboolean should_close; +} EditorCloseStruct; - if (!cle_type) { - static const GTypeInfo cle_info = { - sizeof (EContactListEditorClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_contact_list_editor_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EContactListEditor), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_contact_list_editor_init, - }; +struct _EContactListEditorPrivate { - cle_type = g_type_register_static (EAB_TYPE_EDITOR, "EContactListEditor", &cle_info, 0); - } + EBook *book; + EContact *contact; - return cle_type; -} + GladeXML *xml; + GtkTreeModel *model; + ENameSelector *name_selector; + /* Whether we are editing a new contact or an existing one. */ + guint is_new_list : 1; -static void -e_contact_list_editor_class_init (EContactListEditorClass *klass) + /* Whether the contact has been changed since bringing up the + * contact editor. */ + guint changed : 1; + + /* Whether the contact editor will accept modifications. */ + guint editable : 1; + + /* Whether the target book accepts storing of contact lists. */ + guint allows_contact_lists : 1; + + /* Whether an async wombat call is in progress. */ + guint in_async_call : 1; + + /* ID for async load_source call */ + guint load_source_id; + EBook *load_book; +}; + +#define VCARD_TYPE "text/x-vcard" + +enum { + TARGET_TYPE_VCARD, +}; + +static GtkTargetEntry targets[] = { + { VCARD_TYPE, 0, TARGET_TYPE_VCARD }, +}; + +static gpointer parent_class; + +static EContactListEditor * +contact_list_editor_extract (GtkWidget *widget) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - EABEditorClass *editor_class = EAB_EDITOR_CLASS (klass); - - parent_class = g_type_class_ref (EAB_TYPE_EDITOR); - - editor_class->show = e_contact_list_editor_show; - editor_class->raise = e_contact_list_editor_raise; - editor_class->close = e_contact_list_editor_close; - editor_class->save_contact = e_contact_list_editor_save_contact; - editor_class->is_valid = e_contact_list_editor_is_valid; - editor_class->is_changed = e_contact_list_editor_is_changed; - editor_class->get_window = e_contact_list_editor_get_window; - - object_class->set_property = e_contact_list_editor_set_property; - object_class->get_property = e_contact_list_editor_get_property; - object_class->dispose = e_contact_list_editor_dispose; - - g_object_class_install_property (object_class, PROP_BOOK, - g_param_spec_object ("book", - _("Book"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_BOOK, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_CONTACT, - g_param_spec_object ("contact", - _("Contact"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_CONTACT, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_IS_NEW_LIST, - g_param_spec_boolean ("is_new_list", - _("Is New List"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_EDITABLE, - g_param_spec_boolean ("editable", - _("Editable"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (widget); + return g_object_get_data (G_OBJECT (toplevel), TOPLEVEL_KEY); } static void -e_contact_list_editor_init (EContactListEditor *editor) +contact_list_editor_scroll_to_end (EContactListEditor *editor) { - GladeXML *gui; - GList *icon_list; - char *gladefile; - - editor->contact = NULL; - editor->changed = FALSE; - editor->image_set = FALSE; - editor->editable = TRUE; - editor->allows_contact_lists = TRUE; - editor->in_async_call = FALSE; - editor->is_new_list = FALSE; - - editor->load_source_id = 0; - editor->load_book = NULL; - - gladefile = g_build_filename (EVOLUTION_GLADEDIR, - "contact-list-editor.glade", - NULL); - gui = glade_xml_new (gladefile, NULL, NULL); - g_free (gladefile); - - editor->gui = gui; - - editor->app = glade_xml_get_widget (gui, "contact list editor"); - - editor->table = glade_xml_get_widget (gui, "contact-list-table"); - editor->model = g_object_get_data (G_OBJECT(editor->table), "model"); - - /* XXX need this for libglade-2 it seems */ - gtk_widget_show (editor->table); - - editor->add_button = glade_xml_get_widget (editor->gui, "add-email-button"); - editor->remove_button = glade_xml_get_widget (editor->gui, "remove-button"); - editor->select_button = glade_xml_get_widget (editor->gui, "select-button"); - - editor->email_entry = glade_xml_get_widget (gui, "email-entry"); - editor->list_name_entry = glade_xml_get_widget (gui, "list-name-entry"); - editor->list_image = glade_xml_get_widget (gui, "list-image"); - editor->visible_addrs_checkbutton = glade_xml_get_widget (gui, "visible-addrs-checkbutton"); - editor->source_menu = glade_xml_get_widget (gui, "source-combo-box-source"); - - editor->ok_button = glade_xml_get_widget (gui, "ok-button"); - editor->cancel_button = glade_xml_get_widget (gui, "cancel-button"); - - /* connect signals */ - g_signal_connect (editor->add_button, - "clicked", G_CALLBACK(add_email_cb), editor); - g_signal_connect (editor->email_entry, - "activate", G_CALLBACK(add_email_cb), editor); - g_signal_connect ((ENameSelectorEntry *)editor->email_entry, - "updated", G_CALLBACK(email_match_selected), editor); - g_signal_connect (editor->remove_button, - "clicked", G_CALLBACK(remove_entry_cb), editor); - g_signal_connect (editor->select_button, - "clicked", G_CALLBACK(select_cb), editor); - g_signal_connect (editor->list_name_entry, - "changed", G_CALLBACK(list_name_changed_cb), editor); - g_signal_connect (editor->visible_addrs_checkbutton, - "toggled", G_CALLBACK(visible_addrs_toggled_cb), editor); - g_signal_connect (editor->email_entry, - "key-press-event", G_CALLBACK(email_key_pressed), editor); - - e_table_drag_dest_set (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), - 0, list_drag_types, num_list_drag_types, GDK_ACTION_LINK); - - g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), - "table_drag_motion", G_CALLBACK(table_drag_motion_cb), editor); - g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), - "table_drag_drop", G_CALLBACK (table_drag_drop_cb), editor); - g_signal_connect (e_table_scrolled_get_table (E_TABLE_SCROLLED (editor->table)), - "table_drag_data_received", G_CALLBACK(table_drag_data_received_cb), editor); - - g_signal_connect (editor->ok_button, - "clicked", G_CALLBACK(save_and_close_cb), editor); - g_signal_connect (editor->cancel_button, - "clicked", G_CALLBACK(close_cb), editor); - - - g_signal_connect (editor->list_image, - "changed", G_CALLBACK(list_image_changed_cb), editor); - - g_signal_connect (editor->source_menu, - "changed", G_CALLBACK (source_changed_cb), editor); - - command_state_changed (editor); - - /* Connect to the deletion of the dialog */ - g_signal_connect (editor->app, "delete_event", - G_CALLBACK (app_delete_event_cb), editor); - - gtk_dialog_set_has_separator (GTK_DIALOG (editor->app), FALSE); - - /* set the icon */ - icon_list = e_icon_factory_get_icon_list ("stock_contact-list"); - if (icon_list) { - gtk_window_set_icon_list (GTK_WINDOW (editor->app), icon_list); - g_list_foreach (icon_list, (GFunc) g_object_unref, NULL); - g_list_free (icon_list); - } + GtkTreeView *view; + GtkTreePath *path; + gint n_rows; - gtk_widget_show_all (editor->app); + view = GTK_TREE_VIEW (WIDGET (TREE_VIEW)); + n_rows = gtk_tree_model_iter_n_children (editor->priv->model, NULL); + + path = gtk_tree_path_new_from_indices (n_rows - 1, -1); + gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0., 0.); + gtk_tree_view_set_cursor (view, path, NULL, FALSE); + gtk_tree_path_free (path); } static void -new_target_cb (EBook *new_book, EBookStatus status, EContactListEditor *editor) +contact_list_editor_update (EContactListEditor *editor) { - editor->load_source_id = 0; - editor->load_book = NULL; + EContactListEditorPrivate *priv = editor->priv; - if (status != E_BOOK_ERROR_OK || new_book == NULL) { - eab_load_error_dialog (NULL, e_book_get_source (new_book), status); + gtk_widget_set_sensitive ( + WIDGET (OK_BUTTON), + eab_editor_is_valid (EAB_EDITOR (editor)) && + priv->allows_contact_lists); - e_source_combo_box_set_active ( - E_SOURCE_COMBO_BOX (editor->source_menu), - e_book_get_source (editor->book)); + gtk_widget_set_sensitive ( + WIDGET (SOURCE_MENU), priv->is_new_list); +} - if (new_book) - g_object_unref (new_book); - return; - } - e_contact_store_add_book (((ENameSelectorEntry *)editor->email_entry)->contact_store, new_book); +static void +contact_list_editor_notify_cb (EContactListEditor *editor, + GParamSpec *pspec) +{ + EContactListEditorPrivate *priv = editor->priv; + gboolean sensitive; - g_object_set (editor, "book", new_book, NULL); - g_object_unref (new_book); + sensitive = priv->editable && priv->allows_contact_lists; + + gtk_widget_set_sensitive (WIDGET (LIST_NAME_ENTRY), sensitive); + gtk_widget_set_sensitive (WIDGET (MEMBERS_VBOX), sensitive); } static void -cancel_load (EContactListEditor *editor) +contact_list_editor_add_email (EContactListEditor *editor) { - if (editor->load_source_id) { - addressbook_load_cancel (editor->load_source_id); - editor->load_source_id = 0; - - g_object_unref (editor->load_book); - editor->load_book = NULL; + EContactListEditorPrivate *priv = editor->priv; + EContactListModel *model; + GtkEntry *entry; + const gchar *text; + + entry = GTK_ENTRY (WIDGET (EMAIL_ENTRY)); + model = E_CONTACT_LIST_MODEL (priv->model); + + text = gtk_entry_get_text (entry); + if (text != NULL && *text != '\0') { + e_contact_list_model_add_email (model, text); + contact_list_editor_scroll_to_end (editor); + priv->changed = TRUE; } + + gtk_entry_set_text (entry, ""); + contact_list_editor_update (editor); } static void -source_changed_cb (ESourceComboBox *source_combo_box, EContactListEditor *editor) +contact_list_editor_book_loaded (EBook *new_book, + EBookStatus status, + EContactListEditor *editor) { - ESource *source; - - source = e_source_combo_box_get_active (source_combo_box); + EContactListEditorPrivate *priv = editor->priv; + ENameSelectorEntry *entry; - cancel_load (editor); + priv->load_source_id = 0; + priv->load_book = NULL; - if (e_source_equal (e_book_get_source (editor->book), source)) + if (status != E_BOOK_ERROR_OK || new_book == NULL) { + eab_load_error_dialog ( + NULL, e_book_get_source (new_book), status); + e_source_combo_box_set_active ( + E_SOURCE_COMBO_BOX (WIDGET (SOURCE_MENU)), + e_book_get_source (priv->book)); + if (new_book) + g_object_unref (new_book); return; + } - editor->load_book = e_book_new (source, NULL); - editor->load_source_id = addressbook_load (editor->load_book, - (EBookCallback) new_target_cb, editor); + entry = E_NAME_SELECTOR_ENTRY (WIDGET (EMAIL_ENTRY)); + e_contact_store_add_book (entry->contact_store, new_book); + e_contact_list_editor_set_book (editor, new_book); + g_object_unref (new_book); } static void -e_contact_list_editor_dispose (GObject *object) +contact_list_editor_cancel_load (EContactListEditor *editor) { - EContactListEditor *editor = E_CONTACT_LIST_EDITOR (object); + EContactListEditorPrivate *priv = editor->priv; - cancel_load (editor); + if (priv->load_source_id == 0) + return; - if (editor->name_selector) { - g_object_unref (editor->name_selector); - editor->name_selector = NULL; - } + addressbook_load_cancel (priv->load_source_id); + priv->load_source_id = 0; - if (G_OBJECT_CLASS (parent_class)->dispose) - (* G_OBJECT_CLASS (parent_class)->dispose) (object); + g_object_unref (priv->load_book); + priv->load_book = NULL; } -typedef struct { - EContactListEditor *cle; - gboolean should_close; -} EditorCloseStruct; +static gboolean +contact_list_editor_contact_exists (EContactListModel *model, + const gchar *email) +{ + const gchar *tag = "addressbook:ask-list-add-exists"; + + if (!e_contact_list_model_has_email (model, email)) + return FALSE; + + return (e_error_run (NULL, tag, email) != GTK_RESPONSE_YES); +} static void -list_added_cb (EBook *book, EBookStatus status, const char *id, EditorCloseStruct *ecs) +contact_list_editor_list_added_cb (EBook *book, + EBookStatus status, + const gchar *id, + EditorCloseStruct *ecs) { - EContactListEditor *cle = ecs->cle; + EContactListEditor *editor = ecs->editor; + EContactListEditorPrivate *priv = editor->priv; gboolean should_close = ecs->should_close; - if (cle->app) - gtk_widget_set_sensitive (cle->app, TRUE); - cle->in_async_call = FALSE; + gtk_widget_set_sensitive (WIDGET (DIALOG), TRUE); + priv->in_async_call = FALSE; - e_contact_set (cle->contact, E_CONTACT_UID, (char*)id); + e_contact_set (priv->contact, E_CONTACT_UID, (gchar *) id); - eab_editor_contact_added (EAB_EDITOR (cle), status, cle->contact); + eab_editor_contact_added ( + EAB_EDITOR (editor), status, priv->contact); if (status == E_BOOK_ERROR_OK) { - cle->is_new_list = FALSE; + priv->is_new_list = FALSE; if (should_close) - eab_editor_close (EAB_EDITOR (cle)); + eab_editor_close (EAB_EDITOR (editor)); else - command_state_changed (cle); + contact_list_editor_update (editor); } - g_object_unref (cle); + g_object_unref (editor); g_free (ecs); } static void -list_modified_cb (EBook *book, EBookStatus status, EditorCloseStruct *ecs) +contact_list_editor_list_modified_cb (EBook *book, + EBookStatus status, + EditorCloseStruct *ecs) { - EContactListEditor *cle = ecs->cle; + EContactListEditor *editor = ecs->editor; + EContactListEditorPrivate *priv = editor->priv; gboolean should_close = ecs->should_close; - if (cle->app) - gtk_widget_set_sensitive (cle->app, TRUE); - cle->in_async_call = FALSE; + gtk_widget_set_sensitive (WIDGET (DIALOG), TRUE); + priv->in_async_call = FALSE; - eab_editor_contact_modified (EAB_EDITOR (cle), status, cle->contact); + eab_editor_contact_modified ( + EAB_EDITOR (editor), status, priv->contact); if (status == E_BOOK_ERROR_OK) { if (should_close) - eab_editor_close (EAB_EDITOR (cle)); + eab_editor_close (EAB_EDITOR (editor)); } - g_object_unref (cle); /* release ref held for ebook callback */ + g_object_unref (editor); g_free (ecs); } static void -save_contact (EContactListEditor *cle, gboolean should_close) +contact_list_editor_render_destination (GtkTreeViewColumn *column, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter) { - extract_info (cle); - - if (cle->book) { - EditorCloseStruct *ecs = g_new(EditorCloseStruct, 1); - - ecs->cle = cle; - g_object_ref (cle); - ecs->should_close = should_close; + /* XXX Would be nice if EDestination had a text property + * that we could just bind the GtkCellRenderer to. */ - if (cle->app) - gtk_widget_set_sensitive (cle->app, FALSE); - cle->in_async_call = TRUE; + EDestination *destination; + const gchar *textrep; - if (cle->is_new_list) - eab_merging_book_add_contact (cle->book, cle->contact, (EBookIdCallback)list_added_cb, ecs); - else - eab_merging_book_commit_contact (cle->book, cle->contact, (EBookCallback)list_modified_cb, ecs); - - cle->changed = FALSE; - } + gtk_tree_model_get (model, iter, 0, &destination, -1); + textrep = e_destination_get_textrep (destination, TRUE); + g_object_set (renderer, "text", textrep, NULL); + g_object_unref (destination); } -static gboolean -is_named (EContactListEditor *editor) +static void +contact_list_editor_row_deleted_cb (GtkTreeModel *model, + GtkTreePath *path, + EContactListEditor *editor) { - char *string = gtk_editable_get_chars(GTK_EDITABLE (editor->list_name_entry), 0, -1); - gboolean named = FALSE; - - if (string && *string) { - named = TRUE; - } - - g_free (string); + gint n_children; - return named; + n_children = gtk_tree_model_iter_n_children (model, NULL); + gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), n_children > 0); } static void -e_contact_list_editor_save_contact (EABEditor *editor, gboolean should_close) +contact_list_editor_row_inserted_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + EContactListEditor *editor) { - EContactListEditor *cle = E_CONTACT_LIST_EDITOR (editor); - - save_contact (cle, should_close); + gtk_widget_set_sensitive (WIDGET (REMOVE_BUTTON), TRUE); } -static gboolean -e_contact_list_editor_is_valid (EABEditor *editor) -{ - EContactListEditor *cle = E_CONTACT_LIST_EDITOR (editor); +/*********************** Autoconnected Signal Handlers ***********************/ - return is_named (cle); -} +void +contact_list_editor_add_button_clicked_cb (GtkWidget *widget); -static gboolean -e_contact_list_editor_is_changed (EABEditor *editor) +void +contact_list_editor_add_button_clicked_cb (GtkWidget *widget) { - EContactListEditor *cle = E_CONTACT_LIST_EDITOR (editor); + EContactListEditor *editor; - return cle->changed; -} + editor = contact_list_editor_extract (widget); -static GtkWindow* -e_contact_list_editor_get_window (EABEditor *editor) -{ - return GTK_WINDOW (E_CONTACT_LIST_EDITOR (editor)->app); + contact_list_editor_add_email (editor); } -static void -close_cb (GtkWidget *widget, EContactListEditor *cle) -{ - eab_editor_prompt_to_save_changes (EAB_EDITOR (cle), GTK_WINDOW (cle->app)); -} +void +contact_list_editor_cancel_button_clicked_cb (GtkWidget *widget); -static void -save_and_close_cb (GtkWidget *widget, EContactListEditor *cle) +void +contact_list_editor_cancel_button_clicked_cb (GtkWidget *widget) { - EABEditor *editor = EAB_EDITOR (cle); - if (! (cle->editable && cle->allows_contact_lists)) - eab_editor_close(editor); - else - save_contact (cle, TRUE); + EContactListEditor *editor; + GtkWindow *window; + + editor = contact_list_editor_extract (widget); + window = GTK_WINDOW (WIDGET (DIALOG)); + + eab_editor_prompt_to_save_changes (EAB_EDITOR (editor), window); } -static void -contact_list_editor_destroy_notify (gpointer data, - GObject *where_the_object_was) +void +contact_list_editor_check_button_toggled_cb (GtkWidget *widget); + +void +contact_list_editor_check_button_toggled_cb (GtkWidget *widget) { - eab_editor_remove (EAB_EDITOR (data)); + EContactListEditor *editor; + + editor = contact_list_editor_extract (widget); + + editor->priv->changed = TRUE; + contact_list_editor_update (editor); } -EContactListEditor * -e_contact_list_editor_new (EBook *book, - EContact *list_contact, - gboolean is_new_list, - gboolean editable) +gboolean +contact_list_editor_delete_event_cb (GtkWidget *widget, + GdkEvent *event); + +gboolean +contact_list_editor_delete_event_cb (GtkWidget *widget, + GdkEvent *event) { - EContactListEditor *ce = g_object_new (E_TYPE_CONTACT_LIST_EDITOR, NULL); + EContactListEditor *editor; + GtkWindow *window; - eab_editor_add (EAB_EDITOR (ce)); - g_object_weak_ref (G_OBJECT (ce), contact_list_editor_destroy_notify, ce); + editor = contact_list_editor_extract (widget); + window = GTK_WINDOW (WIDGET (DIALOG)); - g_object_set (ce, - "book", book, - "contact", list_contact, - "is_new_list", is_new_list, - "editable", editable, - NULL); + /* If we're in an async call, don't allow the dialog to close. */ + if (!editor->priv->in_async_call) + eab_editor_prompt_to_save_changes ( + EAB_EDITOR (editor), window); - return ce; + return TRUE; } -static void -e_contact_list_editor_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +void +contact_list_editor_drag_data_received_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, + guint info, + guint time); + +void +contact_list_editor_drag_data_received_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, + guint info, + guint time) { EContactListEditor *editor; + EContactListModel *model; + gchar *target_type; + gboolean changed = FALSE; + gboolean handled = FALSE; + GList *list, *iter; + + editor = contact_list_editor_extract (widget); + + model = E_CONTACT_LIST_MODEL (editor->priv->model); + target_type = gdk_atom_name (selection_data->target); + + if (strcmp (target_type, VCARD_TYPE) != 0) + goto exit; - editor = E_CONTACT_LIST_EDITOR (object); + list = eab_contact_list_from_string ((gchar *) selection_data->data); - switch (prop_id){ - case PROP_BOOK: { - gboolean changed; + if (list != NULL) + handled = TRUE; - if (editor->book) - g_object_unref (editor->book); - editor->book = E_BOOK(g_value_get_object (value)); - g_object_ref (editor->book); - /* XXX more here about editable/etc. */ + for (iter = list; iter != NULL; iter = iter->next) { + EContact *contact = iter->data; + const gchar *email; - changed = (editor->allows_contact_lists != e_book_check_static_capability (editor->book, - "contact-lists")); - editor->allows_contact_lists = e_book_check_static_capability (editor->book, - "contact-lists"); + if (e_contact_get (contact, E_CONTACT_IS_LIST)) + continue; - if (changed) { - set_editable (editor); - command_state_changed (editor); + email = e_contact_get (contact, E_CONTACT_EMAIL_1); + if (email == NULL) { + g_warning ( + "Contact with no email-ids listed " + "can't be added to a Contact-List"); + continue; + } + + if (!contact_list_editor_contact_exists (model, email)) { + /* Hard-wired for default e-mail */ + e_contact_list_model_add_contact (model, contact, 0); + changed = TRUE; } - break; } - case PROP_CONTACT: - if (editor->contact) - g_object_unref (editor->contact); - editor->contact = e_contact_duplicate(E_CONTACT(g_value_get_object (value))); - fill_in_info(editor); - editor->changed = FALSE; - command_state_changed (editor); - break; - case PROP_IS_NEW_LIST: { - gboolean new_value = g_value_get_boolean (value); - gboolean changed = (editor->is_new_list != new_value); - - editor->is_new_list = new_value; - - if (changed) - command_state_changed (editor); - break; + + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); + + contact_list_editor_scroll_to_end (editor); + + if (changed) { + editor->priv->changed = TRUE; + contact_list_editor_update (editor); } - case PROP_EDITABLE: { - gboolean new_value = g_value_get_boolean (value); - gboolean changed = (editor->editable != new_value); - editor->editable = new_value; +exit: + gtk_drag_finish (context, handled, FALSE, time); +} + +gboolean +contact_list_editor_drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + guint time); + +gboolean +contact_list_editor_drag_drop_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + guint time) +{ + EContactListEditor *editor; + GList *iter; + + editor = contact_list_editor_extract (widget); - if (changed) { - set_editable (editor); - command_state_changed (editor); + for (iter = context->targets; iter != NULL; iter = iter->next) { + GdkAtom target = GDK_POINTER_TO_ATOM (iter->data); + gchar *possible_type; + gboolean match; + + possible_type = gdk_atom_name (target); + match = (strcmp (possible_type, VCARD_TYPE) == 0); + g_free (possible_type); + + if (match) { + gtk_drag_get_data (widget, context, target, time); + return TRUE; } - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; } + + return FALSE; } -static void -e_contact_list_editor_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) +gboolean +contact_list_editor_drag_motion_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + guint time); + +gboolean +contact_list_editor_drag_motion_cb (GtkWidget *widget, + GdkDragContext *context, + gint x, gint y, + guint time) { EContactListEditor *editor; + GList *iter; - editor = E_CONTACT_LIST_EDITOR (object); + editor = contact_list_editor_extract (widget); - switch (prop_id) { - case PROP_BOOK: - g_value_set_object (value, editor->book); - break; + for (iter = context->targets; iter != NULL; iter = iter->next) { + GdkAtom target = GDK_POINTER_TO_ATOM (iter->data); + gchar *possible_type; + gboolean match; - case PROP_CONTACT: - extract_info(editor); - g_value_set_object (value, editor->contact); - break; - - case PROP_IS_NEW_LIST: - g_value_set_boolean (value, editor->is_new_list); - break; + possible_type = gdk_atom_name (target); + match = (strcmp (possible_type, VCARD_TYPE) == 0); + g_free (possible_type); - case PROP_EDITABLE: - g_value_set_boolean (value, editor->editable); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + if (match) { + gdk_drag_status (context, GDK_ACTION_LINK, time); + return TRUE; + } } + + return FALSE; } -static void -e_contact_list_editor_show (EABEditor *editor) +void +contact_list_editor_email_entry_activate_cb (GtkWidget *widget); + +void +contact_list_editor_email_entry_activate_cb (GtkWidget *widget) { - EContactListEditor *cle = E_CONTACT_LIST_EDITOR (editor); - gtk_widget_show (cle->app); + EContactListEditor *editor; + + editor = contact_list_editor_extract (widget); + + contact_list_editor_add_email (editor); } -static void -e_contact_list_editor_raise (EABEditor *editor) +void +contact_list_editor_email_entry_changed_cb (GtkWidget *widget); + +void +contact_list_editor_email_entry_changed_cb (GtkWidget *widget) { - EContactListEditor *cle = E_CONTACT_LIST_EDITOR (editor); - gdk_window_raise (GTK_WIDGET (cle->app)->window); + EContactListEditor *editor; + const gchar *text; + gboolean sensitive; + + editor = contact_list_editor_extract (widget); + text = gtk_entry_get_text (GTK_ENTRY (widget)); + + sensitive = (text != NULL && *text != '\0'); + gtk_widget_set_sensitive (WIDGET (ADD_BUTTON), sensitive); } -static void -e_contact_list_editor_close (EABEditor *editor) +gboolean +contact_list_editor_email_entry_key_press_event_cb (GtkWidget *widget, + GdkEventKey *event); + +gboolean +contact_list_editor_email_entry_key_press_event_cb (GtkWidget *widget, + GdkEventKey *event) { - EContactListEditor *cle = E_CONTACT_LIST_EDITOR (editor); - g_return_if_fail (cle->app != NULL); + EContactListEditor *editor; - gtk_widget_destroy (cle->app); - cle->app = NULL; + editor = contact_list_editor_extract (widget); - eab_editor_closed (EAB_EDITOR (cle)); + if (event->keyval == GDK_comma || event->keyval == GDK_Return) { + g_signal_emit_by_name (widget, "activate", 0); + contact_list_editor_add_email (editor); + + return TRUE; + } + + return FALSE; } -GtkWidget * -e_contact_list_editor_create_table(gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2); +void +contact_list_editor_email_entry_updated_cb (GtkWidget *widget, + EDestination *destination); -GtkWidget * -e_contact_list_editor_create_table(gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2) +void +contact_list_editor_email_entry_updated_cb (GtkWidget *widget, + EDestination *destination) { + EContactListEditor *editor; + ENameSelectorEntry *entry; + EContactListModel *model; + EDestinationStore *store; + gchar *email; - ETableModel *model; - GtkWidget *table; - char *etspecfile; + editor = contact_list_editor_extract (widget); - model = e_contact_list_model_new (); + entry = E_NAME_SELECTOR_ENTRY (widget); + model = E_CONTACT_LIST_MODEL (editor->priv->model); - etspecfile = g_build_filename (EVOLUTION_ETSPECDIR, - "e-contact-list-editor.etspec", - NULL); - table = e_table_scrolled_new_from_spec_file (model, - NULL, - etspecfile, - NULL); - g_free (etspecfile); + email = g_strdup (e_destination_get_address (destination)); + store = e_name_selector_entry_peek_destination_store (entry); + e_destination_store_remove_destination (store, destination); + gtk_entry_set_text (GTK_ENTRY (WIDGET (EMAIL_ENTRY)), ""); - g_object_set_data(G_OBJECT(table), "model", model); + if (email && *email) { + e_contact_list_model_add_email (model, email); + contact_list_editor_scroll_to_end (editor); + editor->priv->changed = TRUE; + } - return table; + g_free (email); + contact_list_editor_update (editor); } -static gboolean -contact_already_exists (EContactListModel *model, const char *email) +void +contact_list_editor_list_name_entry_changed_cb (GtkWidget *widget); + +void +contact_list_editor_list_name_entry_changed_cb (GtkWidget *widget) { - int row_count; - int row; - char *list_email; - row_count = e_table_model_row_count (E_TABLE_MODEL (model)); - for (row = 0; row < row_count; row ++) { - list_email = (char *) e_destination_get_email(e_contact_list_model_get_destination (model, row)); - if (strcmp (list_email, email) == 0) { - if (e_error_run (NULL, "addressbook:ask-list-add-exists", - email) != GTK_RESPONSE_YES) - return TRUE; - else - return FALSE; - break; - } - } - return FALSE; + EContactListEditor *editor; + const gchar *title; + + editor = contact_list_editor_extract (widget); + + title = gtk_entry_get_text (GTK_ENTRY (widget)); + + if (title == NULL || *title == '\0') + title = _("Contact List Editor"); + + gtk_window_set_title (GTK_WINDOW (WIDGET (DIALOG)), title); + + editor->priv->changed = TRUE; + contact_list_editor_update (editor); } -static void -add_to_model (EContactListEditor *editor, GList *destinations) +void +contact_list_editor_ok_button_clicked_cb (GtkWidget *widget); + +void +contact_list_editor_ok_button_clicked_cb (GtkWidget *widget) { - GList *l; - - for (l = destinations; l; l = g_list_next (l)) { - EDestination *destination = l->data; - if (e_destination_get_email (destination)) { - if (! contact_already_exists (E_CONTACT_LIST_MODEL (editor->model) - , e_destination_get_email (destination))) { - e_contact_list_model_add_destination (E_CONTACT_LIST_MODEL (editor->model), - destination); - } - } - } + EContactListEditor *editor; + gboolean save_contact; + + editor = contact_list_editor_extract (widget); + + save_contact = + editor->priv->editable && + editor->priv->allows_contact_lists; + + if (save_contact) + eab_editor_save_contact (EAB_EDITOR (editor), TRUE); + else + eab_editor_close (EAB_EDITOR (editor)); } -static void -select_names_ok_cb (GtkWidget *widget, gint response, gpointer data) +void +contact_list_editor_remove_button_clicked_cb (GtkWidget *widget); + +void +contact_list_editor_remove_button_clicked_cb (GtkWidget *widget) { - EContactListEditor *ce; - ENameSelectorDialog *name_selector_dialog; - ENameSelectorModel *name_selector_model; - EDestinationStore *destination_store; - GList *destinations; + EContactListEditor *editor; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeView *view; + GList *list, *iter; + + editor = contact_list_editor_extract (widget); + + view = GTK_TREE_VIEW (WIDGET (TREE_VIEW)); + selection = gtk_tree_view_get_selection (view); + list = gtk_tree_selection_get_selected_rows (selection, &model); - ce = E_CONTACT_LIST_EDITOR (data); + /* Convert the GtkTreePaths to GtkTreeRowReferences. */ + for (iter = list; iter != NULL; iter = iter->next) { + GtkTreePath *path = iter->data; - name_selector_dialog = e_name_selector_peek_dialog (ce->name_selector); - gtk_widget_hide (GTK_WIDGET (name_selector_dialog)); + iter->data = gtk_tree_row_reference_new (model, path); + gtk_tree_path_free (path); + } + + /* Delete each row in the list. */ + for (iter = list; iter != NULL; iter = iter->next) { + GtkTreeRowReference *reference = iter->data; + GtkTreePath *path; + GtkTreeIter iter; + gboolean valid; - name_selector_model = e_name_selector_peek_model (ce->name_selector); - e_name_selector_model_peek_section (name_selector_model, "Members", NULL, &destination_store); - destinations = e_destination_store_list_destinations (destination_store); + path = gtk_tree_row_reference_get_path (reference); + valid = gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + g_assert (valid); - add_to_model (ce, destinations); + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + gtk_tree_row_reference_free (reference); + } - g_list_free (destinations); + g_list_free (list); - ce->changed = TRUE; - command_state_changed (ce); + editor->priv->changed = TRUE; + contact_list_editor_update (editor); } -static void -setup_name_selector (EContactListEditor *editor) +void +contact_list_editor_select_button_clicked_cb (GtkWidget *widget); + +void +contact_list_editor_select_button_clicked_cb (GtkWidget *widget) { - ENameSelectorModel *name_selector_model; - ENameSelectorDialog *name_selector_dialog; + EContactListEditor *editor; + EContactListModel *model; + ENameSelectorDialog *dialog; + EDestinationStore *store; + GList *list, *iter; - if (editor->name_selector) - return; + editor = contact_list_editor_extract (widget); - editor->name_selector = e_name_selector_new (); + model = E_CONTACT_LIST_MODEL (editor->priv->model); + dialog = e_name_selector_peek_dialog (editor->priv->name_selector); + gtk_window_set_title (GTK_WINDOW (dialog), _("Contact List Members")); - name_selector_model = e_name_selector_peek_model (editor->name_selector); - e_name_selector_model_add_section (name_selector_model, "Members", gettext ("_Members"), NULL); + /* We need to empty out the destination store, since we copy its + * contents every time. This sucks, we should really be wired + * directly to the EDestinationStore that the name selector uses + * in true MVC fashion. */ - name_selector_dialog = e_name_selector_peek_dialog (editor->name_selector); - gtk_window_set_title (GTK_WINDOW (name_selector_dialog), _("Contact List Members")); - g_signal_connect (name_selector_dialog, "response", - G_CALLBACK (select_names_ok_cb), editor); + e_name_selector_model_peek_section ( + e_name_selector_peek_model (editor->priv->name_selector), + "Members", NULL, &store); + + list = e_destination_store_list_destinations (store); + + for (iter = list; iter != NULL; iter = iter->next) + e_destination_store_remove_destination (store, iter->data); + + g_list_free (list); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_hide (GTK_WIDGET (dialog)); + + list = e_destination_store_list_destinations (store); + + for (iter = list; iter != NULL; iter = iter->next) { + EDestination *destination = iter->data; + const gchar *email = e_destination_get_email (destination); + + if (email == NULL) + continue; + + if (!contact_list_editor_contact_exists (model, email)) + e_contact_list_model_add_destination ( + model, destination); + } + + g_list_free (list); + + editor->priv->changed = TRUE; + contact_list_editor_update (editor); } -static void -select_cb (GtkWidget *w, EContactListEditor *editor) +void +contact_list_editor_source_menu_changed_cb (GtkWidget *widget); + +void +contact_list_editor_source_menu_changed_cb (GtkWidget *widget) { - ENameSelectorModel *name_selector_model; - ENameSelectorDialog *name_selector_dialog; - EDestinationStore *destination_store; - GList *destinations; - GList *l; + EContactListEditor *editor; + ESource *source; - setup_name_selector (editor); + editor = contact_list_editor_extract (widget); + source = e_source_combo_box_get_active (E_SOURCE_COMBO_BOX (widget)); - /* We need to empty out the destination store, since we copy its contents every time. - * This sucks, we should really be wired directly to the EDestinationStore that - * the name selector uses in true MVC fashion. */ + if (e_source_equal (e_book_get_source (editor->priv->book), source)) + return; - name_selector_model = e_name_selector_peek_model (editor->name_selector); - e_name_selector_model_peek_section (name_selector_model, "Members", NULL, &destination_store); - destinations = e_destination_store_list_destinations (destination_store); + editor->priv->load_book = e_book_new (source, NULL); + editor->priv->load_source_id = addressbook_load ( + editor->priv->load_book, (EBookCallback) + contact_list_editor_book_loaded, editor); +} - for (l = destinations; l; l = g_list_next (l)) { - EDestination *destination = l->data; - e_destination_store_remove_destination (destination_store, destination); - } +gboolean +contact_list_editor_tree_view_key_press_event_cb (GtkWidget *widget, + GdkEventKey *event); +gboolean +contact_list_editor_tree_view_key_press_event_cb (GtkWidget *widget, + GdkEventKey *event) +{ + EContactListEditor *editor; - g_list_free (destinations); + editor = contact_list_editor_extract (widget); - name_selector_dialog = e_name_selector_peek_dialog (editor->name_selector); - gtk_widget_show (GTK_WIDGET (name_selector_dialog)); + if (event->keyval == GDK_Delete) { + g_signal_emit_by_name (WIDGET (REMOVE_BUTTON), "clicked"); + return TRUE; + } + + return FALSE; } +/*********************** Glade Custom Widget Factories ***********************/ + GtkWidget * -e_contact_list_editor_create_source_combo_box (gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2); +contact_list_editor_create_source_combo_box (gchar *name, + gchar *string1, + gchar *string2, + gint int1, + gint int2); GtkWidget * -e_contact_list_editor_create_source_combo_box (gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2) +contact_list_editor_create_source_combo_box (gchar *name, + gchar *string1, + gchar *string2, + gint int1, + gint int2) { + const gchar *key = "/apps/evolution/addressbook/sources"; - GtkWidget *combo_box; - GConfClient *gconf_client; + GtkWidget *combo_box; + GConfClient *client; ESourceList *source_list; - gconf_client = gconf_client_get_default (); - source_list = e_source_list_new_for_gconf (gconf_client, "/apps/evolution/addressbook/sources"); - + client = gconf_client_get_default (); + source_list = e_source_list_new_for_gconf (client, key); combo_box = e_source_combo_box_new (source_list); g_object_unref (source_list); + g_object_unref (client); + + g_signal_connect ( + combo_box, "changed", G_CALLBACK ( + contact_list_editor_source_menu_changed_cb), NULL); gtk_widget_show (combo_box); + return combo_box; } GtkWidget * -e_contact_list_editor_create_name_selector (gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2); +contact_list_editor_create_name_selector (gchar *name, + gchar *string1, + gchar *string2, + gint int1, + gint int2); GtkWidget * -e_contact_list_editor_create_name_selector (gchar *name, - gchar *string1, gchar *string2, - gint int1, gint int2) +contact_list_editor_create_name_selector (gchar *name, + gchar *string1, + gchar *string2, + gint int1, + gint int2) { - ENameSelectorModel *name_selector_model; ENameSelectorEntry *name_selector_entry; - ENameSelector *name_selector = e_name_selector_new (); + ENameSelector *name_selector; + + name_selector = e_name_selector_new (); - name_selector_model = e_name_selector_peek_model (name_selector); - e_name_selector_model_add_section (name_selector_model, "Members", "Members", NULL); + e_name_selector_model_add_section ( + e_name_selector_peek_model (name_selector), + "Members", "Members", NULL); - name_selector_entry = e_name_selector_peek_section_entry (name_selector, "Members"); + name_selector_entry = e_name_selector_peek_section_entry ( + name_selector, "Members"); - e_name_selector_entry_set_contact_editor_func (name_selector_entry, e_contact_editor_new); - e_name_selector_entry_set_contact_list_editor_func (name_selector_entry, e_contact_list_editor_new); + e_name_selector_entry_set_contact_editor_func ( + name_selector_entry, e_contact_editor_new); + e_name_selector_entry_set_contact_list_editor_func ( + name_selector_entry, e_contact_list_editor_new); gtk_widget_show (GTK_WIDGET (name_selector_entry)); - return (GtkWidget *)name_selector_entry; + g_signal_connect ( + name_selector_entry, "activate", G_CALLBACK ( + contact_list_editor_email_entry_activate_cb), NULL); + g_signal_connect ( + name_selector_entry, "changed", G_CALLBACK ( + contact_list_editor_email_entry_changed_cb), NULL); + g_signal_connect ( + name_selector_entry, "key-press-event", G_CALLBACK ( + contact_list_editor_email_entry_key_press_event_cb), NULL); + g_signal_connect ( + name_selector_entry, "updated", G_CALLBACK ( + contact_list_editor_email_entry_updated_cb), NULL); + + return GTK_WIDGET (name_selector_entry); } +/**************************** EABEditor Callbacks ****************************/ + static void -add_email_cb (GtkWidget *w, EContactListEditor *editor) +contact_list_editor_show (EABEditor *editor) { - GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (editor->table)); - const char *text = gtk_entry_get_text (GTK_ENTRY(editor->email_entry)); - - if (text && *text) { - e_contact_list_model_add_email (E_CONTACT_LIST_MODEL(editor->model), text); - - /* Skip to the end of the list */ - if (adj->upper - adj->lower > adj->page_size) - gtk_adjustment_set_value (adj, adj->upper); - - editor->changed = TRUE; + gtk_widget_show (WIDGET (DIALOG)); +} - } +static void +contact_list_editor_close (EABEditor *editor) +{ + gtk_widget_destroy (WIDGET (DIALOG)); + eab_editor_closed (editor); +} - gtk_entry_set_text (GTK_ENTRY(editor->email_entry), ""); - command_state_changed (editor); +static void +contact_list_editor_raise (EABEditor *editor) +{ + gdk_window_raise (WIDGET (DIALOG)->window); } static void -email_match_selected (GtkWidget *w, EDestination *destination, EContactListEditor *editor) +contact_list_editor_save_contact (EABEditor *eab_editor, + gboolean should_close) { - char *email; - EDestinationStore *store; - GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (editor->table)); + EContactListEditor *editor = E_CONTACT_LIST_EDITOR (eab_editor); + EContactListEditorPrivate *priv = editor->priv; + EditorCloseStruct *ecs; + EContact *contact; - email = g_strdup(e_destination_get_address (destination)); - store = e_name_selector_entry_peek_destination_store ((ENameSelectorEntry *)w); - e_destination_store_remove_destination (store, destination); - gtk_entry_set_text (GTK_ENTRY(editor->email_entry), ""); + contact = e_contact_list_editor_get_contact (editor); - if (email && *email) { - e_contact_list_model_add_email (E_CONTACT_LIST_MODEL(editor->model), email); + if (priv->book == NULL) + return; - /* Skip to the end of the list */ - if (adj->upper - adj->lower > adj->page_size) - gtk_adjustment_set_value (adj, adj->upper); + ecs = g_new (EditorCloseStruct, 1); + ecs->editor = g_object_ref (editor); + ecs->should_close = should_close; - editor->changed = TRUE; - } + gtk_widget_set_sensitive (WIDGET (DIALOG), FALSE); + priv->in_async_call = TRUE; - g_free (email); - command_state_changed (editor); + if (priv->is_new_list) + eab_merging_book_add_contact ( + priv->book, contact, (EBookIdCallback) + contact_list_editor_list_added_cb, ecs); + else + eab_merging_book_commit_contact ( + priv->book, contact, (EBookCallback) + contact_list_editor_list_modified_cb, ecs); + + priv->changed = FALSE; } -static void -prepend_selected_rows (int model_row, GList **list) +static gboolean +contact_list_editor_is_valid (EABEditor *editor) { - int *idx = g_new (int, 1); - *idx = model_row; - *list = g_list_append (*list, idx); + GtkEditable *editable; + gboolean valid; + gchar *chars; + + editable = GTK_EDITABLE (WIDGET (LIST_NAME_ENTRY)); + chars = gtk_editable_get_chars (editable, 0, -1); + valid = (chars != NULL && *chars != '\0'); + g_free (chars); + + return valid; } -static void -remove_entry_cb (GtkWidget *w, EContactListEditor *editor) +static gboolean +contact_list_editor_is_changed (EABEditor *editor) { - int *idx = NULL; - GList *list = NULL; - int num_rows_deleted = 0; - e_table_selected_row_foreach (e_table_scrolled_get_table(E_TABLE_SCROLLED(editor->table)), - (EForeachFunc)prepend_selected_rows, &list); - - if (!list) return ; - - for(; list; list=list->next, num_rows_deleted++) { - idx = (int *)(list->data); - e_contact_list_model_remove_row (E_CONTACT_LIST_MODEL (editor->model), (*idx - num_rows_deleted)); - g_free (idx); - list->data = NULL; - } - - list = g_list_first (list); - g_list_free (list); - editor->changed = TRUE; - command_state_changed (editor); + return E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor)->changed; } -static void -list_name_changed_cb (GtkWidget *w, EContactListEditor *editor) +static GtkWindow* +contact_list_editor_get_window (EABEditor *editor) { - char *string = gtk_editable_get_chars(GTK_EDITABLE (w), 0, -1); - char *title; + return GTK_WINDOW (WIDGET (DIALOG)); +} - editor->changed = TRUE; +/***************************** GObject Callbacks *****************************/ - if (string && *string) - title = string; - else - title = _("Contact List Editor"); +static GObject * +contact_list_editor_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObject *object; - gtk_window_set_title (GTK_WINDOW (editor->app), title); + /* Chain up to parent's constructor() method. */ + object = G_OBJECT_CLASS (parent_class)->constructor ( + type, n_construct_properties, construct_properties); - g_free (string); + contact_list_editor_update (E_CONTACT_LIST_EDITOR (object)); - command_state_changed (editor); + return object; } static void -list_image_changed_cb (GtkWidget *w, EContactListEditor *editor) +contact_list_editor_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) { - editor->image_set = TRUE; - editor->changed = TRUE; - command_state_changed (editor); + switch (property_id) { + case PROP_BOOK: + e_contact_list_editor_set_book ( + E_CONTACT_LIST_EDITOR (object), + g_value_get_object (value)); + return; + + case PROP_CONTACT: + e_contact_list_editor_set_contact ( + E_CONTACT_LIST_EDITOR (object), + g_value_get_object (value)); + return; + + case PROP_IS_NEW_LIST: + e_contact_list_editor_set_is_new_list ( + E_CONTACT_LIST_EDITOR (object), + g_value_get_boolean (value)); + return; + + case PROP_EDITABLE: + e_contact_list_editor_set_editable ( + E_CONTACT_LIST_EDITOR (object), + g_value_get_boolean (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } static void -visible_addrs_toggled_cb (GtkWidget *w, EContactListEditor *editor) +contact_list_editor_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) { - editor->changed = TRUE; - command_state_changed (editor); + switch (property_id) { + case PROP_BOOK: + g_value_set_object ( + value, + e_contact_list_editor_get_book ( + E_CONTACT_LIST_EDITOR (object))); + return; + + case PROP_CONTACT: + g_value_set_object ( + value, + e_contact_list_editor_get_contact ( + E_CONTACT_LIST_EDITOR (object))); + return; + + case PROP_IS_NEW_LIST: + g_value_set_boolean ( + value, + e_contact_list_editor_get_is_new_list ( + E_CONTACT_LIST_EDITOR (object))); + return; + + case PROP_EDITABLE: + g_value_set_boolean ( + value, + e_contact_list_editor_get_editable ( + E_CONTACT_LIST_EDITOR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } -static gboolean -email_key_pressed (GtkWidget *w, GdkEventKey *event, EContactListEditor *editor) +static void +contact_list_editor_dispose (GObject *object) { + EContactListEditor *editor = E_CONTACT_LIST_EDITOR (object); + EContactListEditorPrivate *priv = editor->priv; - if (event->keyval == GDK_comma || event->keyval == GDK_Return) { - ENameSelectorEntry *entry = (ENameSelectorEntry *)w; + contact_list_editor_cancel_load (editor); - g_signal_emit_by_name (entry, "activate", 0); - add_email_cb (w, editor); + if (priv->name_selector) { + g_object_unref (priv->name_selector); + priv->name_selector = NULL; + } - return TRUE; - } + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} - return FALSE; +/****************************** GType Callbacks ******************************/ + +static void +contact_list_editor_class_init (EContactListEditorClass *class) +{ + GObjectClass *object_class; + EABEditorClass *editor_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EContactListEditorPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->constructor = contact_list_editor_constructor; + object_class->set_property = contact_list_editor_set_property; + object_class->get_property = contact_list_editor_get_property; + object_class->dispose = contact_list_editor_dispose; + + editor_class = EAB_EDITOR_CLASS (class); + editor_class->show = contact_list_editor_show; + editor_class->close = contact_list_editor_close; + editor_class->raise = contact_list_editor_raise; + editor_class->save_contact = contact_list_editor_save_contact; + editor_class->is_valid = contact_list_editor_is_valid; + editor_class->is_changed = contact_list_editor_is_changed; + editor_class->get_window = contact_list_editor_get_window; + + g_object_class_install_property ( + object_class, + PROP_BOOK, + g_param_spec_object ( + "book", + _("Book"), + /*_( */"XXX blurb" /*)*/, + E_TYPE_BOOK, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CONTACT, + g_param_spec_object ( + "contact", + _("Contact"), + /*_( */"XXX blurb" /*)*/, + E_TYPE_CONTACT, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_IS_NEW_LIST, + g_param_spec_boolean ( + "is_new_list", + _("Is New List"), + /*_( */"XXX blurb" /*)*/, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_EDITABLE, + g_param_spec_boolean ( + "editable", + _("Editable"), + /*_( */"XXX blurb" /*)*/, + FALSE, + G_PARAM_READWRITE)); } static void -set_editable (EContactListEditor *editor) +contact_list_editor_init (EContactListEditor *editor) { - gtk_widget_set_sensitive (editor->email_entry, editor->editable && editor->allows_contact_lists); - gtk_widget_set_sensitive (editor->list_name_entry, editor->editable && editor->allows_contact_lists); - gtk_widget_set_sensitive (editor->add_button, editor->editable && editor->allows_contact_lists); - gtk_widget_set_sensitive (editor->remove_button, editor->editable && editor->allows_contact_lists); - gtk_widget_set_sensitive (editor->select_button, editor->editable && editor->allows_contact_lists); - gtk_widget_set_sensitive (editor->cancel_button, editor->editable && editor->allows_contact_lists); - gtk_widget_set_sensitive (editor->visible_addrs_checkbutton, editor->editable && editor->allows_contact_lists); + EContactListEditorPrivate *priv; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + GtkTreeView *view; + gchar *filename; + + priv = E_CONTACT_LIST_EDITOR_GET_PRIVATE (editor); + + priv->editable = TRUE; + priv->allows_contact_lists = TRUE; + + filename = g_build_filename ( + EVOLUTION_GLADEDIR, "contact-list-editor.glade", NULL); + priv->xml = glade_xml_new (filename, NULL, NULL); + glade_xml_signal_autoconnect (priv->xml); + g_free (filename); + + /* Embed a pointer to the EContactListEditor in the top-level + * widget. Signal handlers can then access the pointer from any + * child widget by calling contact_list_editor_extract(widget). */ + g_object_set_data (G_OBJECT (WIDGET (DIALOG)), TOPLEVEL_KEY, editor); + + view = GTK_TREE_VIEW (WIDGET (TREE_VIEW)); + priv->model = e_contact_list_model_new (); + gtk_tree_view_set_model (view, priv->model); + + gtk_tree_selection_set_mode ( + gtk_tree_view_get_selection (view), GTK_SELECTION_MULTIPLE); + gtk_tree_view_enable_model_drag_dest ( + view, targets, G_N_ELEMENTS (targets), GDK_ACTION_LINK); + + g_signal_connect ( + priv->model, "row-deleted", + G_CALLBACK (contact_list_editor_row_deleted_cb), editor); + g_signal_connect ( + priv->model, "row-inserted", + G_CALLBACK (contact_list_editor_row_inserted_cb), editor); + + column = gtk_tree_view_column_new (); + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_append_column (view, column); + + gtk_tree_view_column_set_cell_data_func ( + column, renderer, (GtkTreeCellDataFunc) + contact_list_editor_render_destination, NULL, NULL); + + priv->name_selector = e_name_selector_new (); + + e_name_selector_model_add_section ( + e_name_selector_peek_model (priv->name_selector), + "Members", _("_Members"), NULL); + + g_signal_connect ( + editor, "notify::book", + G_CALLBACK (contact_list_editor_notify_cb), NULL); + g_signal_connect ( + editor, "notify::editable", + G_CALLBACK (contact_list_editor_notify_cb), NULL); + + gtk_widget_show_all (WIDGET (DIALOG)); + + editor->priv = priv; } -/* Callback used when the editor is destroyed */ -static gint -app_delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) +/***************************** Public Interface ******************************/ + +GType +e_contact_list_editor_get_type (void) { - EContactListEditor *ce; + static GType type = 0; - ce = E_CONTACT_LIST_EDITOR (data); + if (G_UNLIKELY (type == 0)) + type = g_type_register_static_simple ( + EAB_TYPE_EDITOR, + "EContactListEditor", + sizeof (EContactListEditorClass), + (GClassInitFunc) contact_list_editor_class_init, + sizeof (EContactListEditor), + (GInstanceInitFunc) contact_list_editor_init, 0); - /* if we're in an async call, don't allow the dialog to close */ - if (ce->in_async_call) - return TRUE; + return type; +} - eab_editor_prompt_to_save_changes (EAB_EDITOR (ce), GTK_WINDOW (ce->app)); - return TRUE; +static void +contact_list_editor_destroy_notify (gpointer data, + GObject *where_the_object_was) +{ + eab_editor_remove (EAB_EDITOR (data)); } -static gboolean -table_drag_motion_cb (ETable *table, int row, int col, - GdkDragContext *context, - gint x, gint y, guint time, EContactListEditor *editor) +EContactListEditor * +e_contact_list_editor_new (EBook *book, + EContact *list_contact, + gboolean is_new_list, + gboolean editable) { - GList *p; + EContactListEditor *editor; - for (p = context->targets; p != NULL; p = p->next) { - char *possible_type; + editor = g_object_new (E_TYPE_CONTACT_LIST_EDITOR, NULL); - possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data)); - if (!strcmp (possible_type, VCARD_TYPE)) { - g_free (possible_type); - gdk_drag_status (context, GDK_ACTION_LINK, time); - return TRUE; - } + eab_editor_add (EAB_EDITOR (editor)); + g_object_weak_ref ( + G_OBJECT (editor), contact_list_editor_destroy_notify, editor); - g_free (possible_type); - } + g_object_set (editor, + "book", book, + "contact", list_contact, + "is_new_list", is_new_list, + "editable", editable, + NULL); - return FALSE; + return editor; } -static gboolean -table_drag_drop_cb (ETable *table, int row, int col, - GdkDragContext *context, - gint x, gint y, guint time, EContactListEditor *editor) +EBook * +e_contact_list_editor_get_book (EContactListEditor *editor) { - GList *p; + g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), NULL); - for (p = context->targets; p != NULL; p = p->next) { - char *possible_type; + return editor->priv->book; +} - possible_type = gdk_atom_name (GDK_POINTER_TO_ATOM (p->data)); - if (!strcmp (possible_type, VCARD_TYPE)) { - g_free (possible_type); - break; - } +void +e_contact_list_editor_set_book (EContactListEditor *editor, + EBook *book) +{ + g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor)); + g_return_if_fail (E_IS_BOOK (book)); - g_free (possible_type); - } + if (editor->priv->book != NULL) + g_object_unref (editor->priv->book); + editor->priv->book = g_object_ref (book); + editor->priv->allows_contact_lists = + e_book_check_static_capability ( + editor->priv->book, "contact-lists"); - if (p) { - gtk_drag_get_data (GTK_WIDGET (table), context, - GDK_POINTER_TO_ATOM (p->data), - time); - return TRUE; - } + contact_list_editor_update (editor); - return FALSE; + g_object_notify (G_OBJECT (editor), "book"); } -static void -table_drag_data_received_cb (ETable *table, int row, int col, - GdkDragContext *context, - gint x, gint y, - GtkSelectionData *selection_data, - guint info, guint time, EContactListEditor *editor) +EContact * +e_contact_list_editor_get_contact (EContactListEditor *editor) { - GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (editor->table)); - char *target_type; - gboolean changed = FALSE; - gboolean handled = FALSE; + GtkTreeModel *model; + EContact *contact; + GtkTreeIter iter; + gboolean iter_valid; + const gchar *text; - target_type = gdk_atom_name (selection_data->target); + g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), NULL); - if (!strcmp (target_type, VCARD_TYPE)) { + model = editor->priv->model; + contact = editor->priv->contact; - GList *contact_list = eab_contact_list_from_string ((char *)selection_data->data); - GList *c; + if (contact == NULL) + return NULL; - if (contact_list) - handled = TRUE; + text = gtk_entry_get_text (GTK_ENTRY (WIDGET (LIST_NAME_ENTRY))); + if (text != NULL && *text != '\0') { + e_contact_set (contact, E_CONTACT_FILE_AS, (gpointer) text); + e_contact_set (contact, E_CONTACT_FULL_NAME, (gpointer) text); + } - for (c = contact_list; c; c = c->next) { - EContact *contact = c->data; + e_contact_set (contact, E_CONTACT_LOGO, NULL); + e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE)); - if (!e_contact_get (contact, E_CONTACT_IS_LIST)) { - if (e_contact_get (contact, E_CONTACT_EMAIL_1)) { - if (! contact_already_exists (E_CONTACT_LIST_MODEL (editor->model) - , e_contact_get (contact, E_CONTACT_EMAIL_1))) { - e_contact_list_model_add_contact (E_CONTACT_LIST_MODEL (editor->model), - contact, - 0 /* Hard-wired for default e-mail */); + e_contact_set ( + contact, E_CONTACT_LIST_SHOW_ADDRESSES, + GINT_TO_POINTER (!gtk_toggle_button_get_active ( + GTK_TOGGLE_BUTTON (WIDGET (CHECK_BUTTON))))); - changed = TRUE; - } - } - else - g_warning ("Contact with no email-ids listed can't be added to a Contact-List"); - } - } - g_list_foreach (contact_list, (GFunc)g_object_unref, NULL); - g_list_free (contact_list); + e_vcard_remove_attributes (E_VCARD (contact), "", EVC_EMAIL); - /* Skip to the end of the list */ - if (adj->upper - adj->lower > adj->page_size) - gtk_adjustment_set_value (adj, adj->upper); + iter_valid = gtk_tree_model_get_iter_first (model, &iter); - if (changed) { - editor->changed = TRUE; - command_state_changed (editor); - } + while (iter_valid) { + EDestination *dest; + EVCardAttribute *attr; + + gtk_tree_model_get (model, &iter, 0, &dest, -1); + attr = e_vcard_attribute_new (NULL, EVC_EMAIL); + e_vcard_add_attribute (E_VCARD (contact), attr); + e_destination_export_to_vcard_attribute (dest, attr); + g_object_unref (dest); + + iter_valid = gtk_tree_model_iter_next (model, &iter); } - gtk_drag_finish (context, handled, FALSE, time); + return contact; } +/* Helper for e_contact_list_editor_set_contact() */ static void -command_state_changed (EContactListEditor *editor) +contact_list_editor_add_destination (EVCardAttribute *attr, + EContactListEditor *editor) { - gboolean valid = eab_editor_is_valid (EAB_EDITOR (editor)); + EDestination *destination; + gchar *contact_uid = NULL; + gint email_num = -1; + GList *list, *iter; + GList *values; + + destination = e_destination_new (); + + list = e_vcard_attribute_get_params (attr); + for (iter = list; iter; iter = iter->next) { + EVCardAttributeParam *param = iter->data; + const gchar *param_name; + gpointer param_data; + + values = e_vcard_attribute_param_get_values (param); + if (values == NULL) + continue; + + param_name = e_vcard_attribute_param_get_name (param); + param_data = values->data; + + if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_CONTACT_UID)) + contact_uid = param_data; + else if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_EMAIL_NUM)) + email_num = atoi (param_data); + else if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_NAME)) + e_destination_set_name (destination, param_data); + else if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_EMAIL)) + e_destination_set_email (destination, param_data); + else if (!g_ascii_strcasecmp (param_name, EVC_X_DEST_HTML_MAIL)) + e_destination_set_html_mail_pref ( + destination, + !g_ascii_strcasecmp (param_data, "true")); + } + + if (contact_uid != NULL) + e_destination_set_contact_uid ( + destination, contact_uid, email_num); - /* FIXME set the ok button to ok */ - gtk_widget_set_sensitive (editor->ok_button, valid && editor->allows_contact_lists); - gtk_widget_set_sensitive (editor->source_menu, editor->is_new_list); - gtk_widget_set_sensitive (glade_xml_get_widget (editor->gui, "source-label"), editor->is_new_list); + e_contact_list_model_add_destination ( + E_CONTACT_LIST_MODEL (editor->priv->model), destination); + + e_vcard_attribute_free (attr); } -static void -extract_info(EContactListEditor *editor) +void +e_contact_list_editor_set_contact (EContactListEditor *editor, + EContact *contact) { - EContact *contact = editor->contact; - if (contact) { - int i; - char *image_data; - gsize image_data_len; - char *string = gtk_editable_get_chars(GTK_EDITABLE (editor->list_name_entry), 0, -1); - - if (string && *string) { - e_contact_set (contact, E_CONTACT_FILE_AS, string); - e_contact_set (contact, E_CONTACT_FULL_NAME, string); - } + EContactListEditorPrivate *priv; - g_free (string); + g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor)); + g_return_if_fail (E_IS_CONTACT (contact)); - e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE)); - e_contact_set (contact, E_CONTACT_LIST_SHOW_ADDRESSES, - GINT_TO_POINTER (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(editor->visible_addrs_checkbutton)))); + priv = editor->priv; - e_vcard_remove_attributes (E_VCARD (contact), "", EVC_EMAIL); + if (priv->contact != NULL) + g_object_unref (priv->contact); + priv->contact = e_contact_duplicate (contact); - /* then refill it from the contact list model */ - for (i = 0; i < e_table_model_row_count (editor->model); i ++) { - const EDestination *dest = e_contact_list_model_get_destination (E_CONTACT_LIST_MODEL (editor->model), i); - EVCardAttribute *attr; + if (priv->contact != NULL) { + const gchar *file_as; + gboolean show_addresses; + GList *email_list; - attr = e_vcard_attribute_new (NULL, EVC_EMAIL); + file_as = e_contact_get_const ( + priv->contact, E_CONTACT_FILE_AS); + email_list = e_contact_get_attributes ( + priv->contact, E_CONTACT_EMAIL); + show_addresses = GPOINTER_TO_INT (e_contact_get ( + priv->contact, E_CONTACT_LIST_SHOW_ADDRESSES)); - e_vcard_add_attribute (E_VCARD (contact), attr); + if (file_as == NULL) + file_as = ""; - e_destination_export_to_vcard_attribute ((EDestination*)dest, attr); - } + gtk_entry_set_text ( + GTK_ENTRY (WIDGET (LIST_NAME_ENTRY)), file_as); - if (editor->image_set - && e_image_chooser_get_image_data (E_IMAGE_CHOOSER (editor->list_image), - &image_data, - &image_data_len)) { - EContactPhoto photo; + gtk_toggle_button_set_active ( + GTK_TOGGLE_BUTTON (WIDGET (CHECK_BUTTON)), + !show_addresses); - photo.type = E_CONTACT_PHOTO_TYPE_INLINED; - photo.data.inlined.mime_type = NULL; - photo.data.inlined.data = (unsigned char *)image_data; - photo.data.inlined.length = image_data_len; + e_contact_list_model_remove_all ( + E_CONTACT_LIST_MODEL (priv->model)); - e_contact_set (contact, E_CONTACT_LOGO, &photo); - g_free (image_data); - } - else { - e_contact_set (contact, E_CONTACT_LOGO, NULL); - } + g_list_foreach ( + email_list, (GFunc) + contact_list_editor_add_destination, editor); + g_list_free (email_list); } + + if (priv->book != NULL) { + e_source_combo_box_set_active ( + E_SOURCE_COMBO_BOX (WIDGET (SOURCE_MENU)), + e_book_get_source (priv->book)); + gtk_widget_set_sensitive ( + WIDGET (SOURCE_MENU), priv->is_new_list); + } + + priv->changed = FALSE; + contact_list_editor_update (editor); + + g_object_notify (G_OBJECT (editor), "contact"); } -static void -fill_in_info(EContactListEditor *editor) +gboolean +e_contact_list_editor_get_is_new_list (EContactListEditor *editor) { - if (editor->contact) { - EContactPhoto *photo; - const char *file_as; - gboolean show_addresses = FALSE; - GList *email_list; - GList *iter; + g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), FALSE); - file_as = e_contact_get_const (editor->contact, E_CONTACT_FILE_AS); - email_list = e_contact_get_attributes (editor->contact, E_CONTACT_EMAIL); - show_addresses = GPOINTER_TO_INT (e_contact_get (editor->contact, E_CONTACT_LIST_SHOW_ADDRESSES)); + return editor->priv->is_new_list; +} - gtk_editable_delete_text (GTK_EDITABLE (editor->list_name_entry), 0, -1); - if (file_as) { - int position = 0; +void +e_contact_list_editor_set_is_new_list (EContactListEditor *editor, + gboolean is_new_list) +{ - gtk_editable_insert_text (GTK_EDITABLE (editor->list_name_entry), file_as, strlen (file_as), &position); - } + g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor)); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(editor->visible_addrs_checkbutton), !show_addresses); - - e_contact_list_model_remove_all (E_CONTACT_LIST_MODEL (editor->model)); - - for (iter = email_list; iter; iter = iter->next) { - EVCardAttribute *attr = iter->data; - GList *p; - EDestination *list_dest = e_destination_new (); - char *contact_uid = NULL; - char *email = NULL; - char *name = NULL; - int email_num = -1; - gboolean html_pref = FALSE; - - for (p = e_vcard_attribute_get_params (attr); p; p = p->next) { - EVCardAttributeParam *param = p->data; - const char *param_name = e_vcard_attribute_param_get_name (param); - if (!g_ascii_strcasecmp (param_name, - EVC_X_DEST_CONTACT_UID)) { - GList *v = e_vcard_attribute_param_get_values (param); - contact_uid = v ? v->data : NULL; - } - else if (!g_ascii_strcasecmp (param_name, - EVC_X_DEST_EMAIL_NUM)) { - GList *v = e_vcard_attribute_param_get_values (param); - email_num = v ? atoi (v->data) : -1; - } - else if (!g_ascii_strcasecmp (param_name, - EVC_X_DEST_NAME)) { - GList *v = e_vcard_attribute_param_get_values (param); - name = v ? v->data : NULL; - } - else if (!g_ascii_strcasecmp (param_name, - EVC_X_DEST_EMAIL)) { - GList *v = e_vcard_attribute_param_get_values (param); - email = v ? v->data : NULL; - } - else if (!g_ascii_strcasecmp (param_name, - EVC_X_DEST_HTML_MAIL)) { - GList *v = e_vcard_attribute_param_get_values (param); - html_pref = v ? !g_ascii_strcasecmp (v->data, "true") : FALSE; - } - } - - if (contact_uid) e_destination_set_contact_uid (list_dest, contact_uid, email_num); - if (name) e_destination_set_name (list_dest, name); - if (email) e_destination_set_email (list_dest, email); - e_destination_set_html_mail_pref (list_dest, html_pref); - - e_contact_list_model_add_destination (E_CONTACT_LIST_MODEL (editor->model), list_dest); - } + editor->priv->is_new_list = is_new_list; + contact_list_editor_update (editor); - g_list_foreach (email_list, (GFunc) e_vcard_attribute_free, NULL); - g_list_free (email_list); + g_object_notify (G_OBJECT (editor), "is_new_list"); +} - photo = e_contact_get (editor->contact, E_CONTACT_LOGO); - if (photo && photo->type == E_CONTACT_PHOTO_TYPE_INLINED) { - e_image_chooser_set_image_data (E_IMAGE_CHOOSER (editor->list_image), (char *)photo->data.inlined.data, photo->data.inlined.length); - e_contact_photo_free (photo); - } - } +gboolean +e_contact_list_editor_get_editable (EContactListEditor *editor) +{ + g_return_val_if_fail (E_IS_CONTACT_LIST_EDITOR (editor), FALSE); - if (editor->book) { - e_source_combo_box_set_active ( - E_SOURCE_COMBO_BOX (editor->source_menu), - e_book_get_source (editor->book)); - gtk_widget_set_sensitive (editor->source_menu, editor->is_new_list); - gtk_widget_set_sensitive (glade_xml_get_widget (editor->gui, "source-label"), editor->is_new_list); - } + return editor->priv->editable; +} + +void +e_contact_list_editor_set_editable (EContactListEditor *editor, + gboolean editable) +{ + g_return_if_fail (E_IS_CONTACT_LIST_EDITOR (editor)); + + editor->priv->editable = editable; + contact_list_editor_update (editor); + + g_object_notify (G_OBJECT (editor), "editable"); } -- cgit v1.2.3