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 --- addressbook/ChangeLog | 23 + addressbook/gui/contact-list-editor/Makefile.am | 9 +- .../contact-list-editor/contact-list-editor.glade | 769 ++++---- .../e-contact-list-editor-marshal.list | 2 - .../contact-list-editor/e-contact-list-editor.c | 2063 +++++++++++--------- .../e-contact-list-editor.etspec | 7 - .../contact-list-editor/e-contact-list-editor.h | 110 +- .../gui/contact-list-editor/e-contact-list-model.c | 307 ++- .../gui/contact-list-editor/e-contact-list-model.h | 68 +- 9 files changed, 1720 insertions(+), 1638 deletions(-) delete mode 100644 addressbook/gui/contact-list-editor/e-contact-list-editor-marshal.list delete mode 100644 addressbook/gui/contact-list-editor/e-contact-list-editor.etspec (limited to 'addressbook') diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index 9badf8e50d..b94ff7c4e2 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,26 @@ +2007-11-28 Matthew Barnes + + ** Fixes bug #489652 + + Migrate the contact list editor from ETable to GtkTreeView and + fix some HIG issues. + + * gui/contact-list-editor/Makefile.am: + Remove e-contact-list-editor.etspec + Remove e-contact-list-editor-marshal.list + + * gui/contact-list-editor/contact-list-editor.glade: + Fix some HIG issues and give all the widgets proper names. + + * gui/contact-list-editor/e-contact-list-model.c: + * gui/contact-list-editor/e-contact-list-model.h: + EContactListModel is now a subclass of GtkListStore. + + * gui/contact-list-editor/e-contact-list.c: + * 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. + 2007-11-23 Milan Crha ** Fix for bug #495711 diff --git a/addressbook/gui/contact-list-editor/Makefile.am b/addressbook/gui/contact-list-editor/Makefile.am index 71516c33bb..76122c2421 100644 --- a/addressbook/gui/contact-list-editor/Makefile.am +++ b/addressbook/gui/contact-list-editor/Makefile.am @@ -10,7 +10,6 @@ INCLUDES = \ -I$(top_srcdir)/addressbook/gui/contact-editor \ -I$(top_builddir)/shell \ -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \ - -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \ -DG_LOG_DOMAIN=\"contact-list-editor\" \ $(EVOLUTION_ADDRESSBOOK_CFLAGS) @@ -35,15 +34,9 @@ libecontactlisteditor_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(EVOLUTION_ADDRESSBOOK_LIBS) -MARSHAL_GENERATED = e-contact-list-editor-marshal.c e-contact-list-editor-marshal.h -@EVO_MARSHAL_RULE@ - glade_DATA = contact-list-editor.glade -etspec_DATA = e-contact-list-editor.etspec BUILT_SOURCES = $(MARSHAL_GENERATED) CLEANFILES = $(BUILT_SOURCES) -EXTRA_DIST = $(glade_DATA) \ - $(etspec_DATA) \ - e-contact-list-editor-marshal.list +EXTRA_DIST = $(glade_DATA) diff --git a/addressbook/gui/contact-list-editor/contact-list-editor.glade b/addressbook/gui/contact-list-editor/contact-list-editor.glade index 64280c2c52..3402e27542 100644 --- a/addressbook/gui/contact-list-editor/contact-list-editor.glade +++ b/addressbook/gui/contact-list-editor/contact-list-editor.glade @@ -1,432 +1,341 @@ - - - + + + - - - True - Contact List Editor - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - -5 - - - - - 0 - False - True - GTK_PACK_END - - - - - - 6 - True - False - 6 - - - - 6 - True - False - 6 - - - - True - 2 - 2 - False - 6 - 6 - - - - True - _List name: - True - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - list-name-entry - - - 0 - 1 - 0 - 1 - fill - - - - - - - True - True - True - True - True - 0 - - True - * - False - - - 1 - 2 - 0 - 1 - - - - - - - True - _Where: - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - e_contact_list_editor_create_source_combo_box - 0 - 0 - Tue, 01 Jun 2004 18:22:38 GMT - - - 1 - 2 - 1 - 2 - fill - fill - - - - - 0 - True - True - - - - - - True - eab_create_image_chooser_widget - stock_addressbook - 0 - 0 - Sat, 23 Jun 2001 05:59:21 GMT - - - 0 - False - False - - - - - 0 - False - False - - - - - - 3 - True - 0 - 0.5 - GTK_SHADOW_ETCHED_IN - - - - 6 - True - False - 6 - - - - True - False - 6 - - - - True - _Type an email address or drag a contact into the list below: - True - False - GTK_JUSTIFY_CENTER - False - False - 0 - 0.5 - 0 - 0 - email-entry - - - 0 - False - False - - - - - - True - e_contact_list_editor_create_name_selector - 0 - 0 - Sat, 27 Aug 2005 13:47:20 GMT - - - 0 - False - True - - - - - - True - e_contact_list_editor_create_table - 0 - 0 - Sat, 23 Jun 2001 06:00:16 GMT - - - 0 - True - True - - - - - - True - True - _Hide addresses when sending mail to this list - True - GTK_RELIEF_NORMAL - True - False - False - True - - - 0 - False - False - - - - - 0 - True - True - - - - - - True - False - 0 - - - - True - - - False - False - GTK_JUSTIFY_CENTER - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - GTK_BUTTONBOX_START - 6 - - - - True - Add an email to the List - True - True - gtk-add - True - GTK_RELIEF_NORMAL - True - - - - - - True - Remove an email address from the List - True - True - gtk-remove - True - GTK_RELIEF_NORMAL - True - - - - - - True - Insert email addresses from Address Book - True - True - _Select - True - GTK_RELIEF_NORMAL - True - - - - - 0 - True - True - - - - - 0 - False - False - - - - - - - - True - Members - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - label_item - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - + + True + 6 + Contact List Editor + GTK_WIN_POS_CENTER + stock_contact-list + GDK_WINDOW_TYPE_HINT_NORMAL + False + + + + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 6 + 2 + 2 + 12 + 12 + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 6 + stock_addressbook + + + 1 + 2 + + + + + + + True + 2 + 2 + 6 + 6 + + + True + 1 + _List name: + True + list-name-entry + + + GTK_FILL + + + + + + True + 1 + _Where: + True + + + 1 + 2 + GTK_FILL + + + + + + True + * + + + + 1 + 2 + + + + + + contact_list_editor_create_source_combo_box + + + 1 + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + + + + + + + True + 6 + + + True + 0 + <b>Members</b> + True + + + False + False + + + + + True + 12 + + + True + 4 + 2 + 6 + 6 + + + + + + + + + + + + True + 0 + _Type an email address or drag a contact into the list below: + True + GTK_JUSTIFY_CENTER + + + + + + + + contact_list_editor_create_name_selector + + + 1 + 2 + + + + + + True + False + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_ETCHED_IN + + + True + False + 0 + + + + + + + + + 2 + 3 + + + + + True + True + _Hide addresses when sending mail to this list + True + 0 + + + + 3 + 4 + + + + + + True + 6 + + + True + False + True + True + True + Add an email to the List + Add an email to the List + gtk-add + True + 0 + 0 + + + + False + False + + + + + True + False + True + True + True + Remove an email address from the List + Remove an email address from the List + gtk-remove + True + 0 + 0 + + + + False + False + 1 + + + + + True + True + True + True + True + Insert email addresses from Address Book + Insert email addresses from Address Book + Select... + 0 + + + + False + False + 2 + + + + + True + + + + + + 3 + + + + + 1 + 2 + 2 + 3 + + + + + + + + 1 + + + + + 2 + 1 + 2 + + + + + 1 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-cancel + True + 0 + + + + + + True + True + gtk-ok + True + 0 + + + + 1 + + + + + False + GTK_PACK_END + + + + + diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor-marshal.list b/addressbook/gui/contact-list-editor/e-contact-list-editor-marshal.list deleted file mode 100644 index 32b8e41ecb..0000000000 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor-marshal.list +++ /dev/null @@ -1,2 +0,0 @@ -INT:OBJECT -NONE:INT,OBJECT 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"); } diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.etspec b/addressbook/gui/contact-list-editor/e-contact-list-editor.etspec deleted file mode 100644 index f4337c3f90..0000000000 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor.etspec +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/addressbook/gui/contact-list-editor/e-contact-list-editor.h b/addressbook/gui/contact-list-editor/e-contact-list-editor.h index 00fb30fae1..41b6078f67 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-editor.h +++ b/addressbook/gui/contact-list-editor/e-contact-list-editor.h @@ -17,13 +17,13 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #ifndef __E_CONTACT_LIST_EDITOR_H__ #define __E_CONTACT_LIST_EDITOR_H__ #include #include #include -#include
#include #include "addressbook/gui/contact-editor/eab-editor.h" @@ -32,66 +32,34 @@ #include #include -G_BEGIN_DECLS +#define E_TYPE_CONTACT_LIST_EDITOR \ + (e_contact_list_editor_get_type ()) +#define E_CONTACT_LIST_EDITOR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditor)) +#define E_CONTACT_LIST_EDITOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditorClass)) +#define E_IS_CONTACT_LIST_EDITOR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_CONTACT_LIST_EDITOR)) +#define E_IS_CONTACT_LIST_EDITOR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((obj), E_TYPE_CONTACT_LIST_EDITOR)) +#define E_CONTACT_LIST_EDITOR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditorClass)) -#define E_TYPE_CONTACT_LIST_EDITOR (e_contact_list_editor_get_type ()) -#define E_CONTACT_LIST_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditor)) -#define E_CONTACT_LIST_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CONTACT_LIST_EDITOR, EContactListEditorClass)) -#define E_IS_CONTACT_LIST_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CONTACT_LIST_EDITOR)) -#define E_IS_CONTACT_LIST_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_CONTACT_LIST_EDITOR)) +G_BEGIN_DECLS -typedef struct _EContactListEditor EContactListEditor; -typedef struct _EContactListEditorClass EContactListEditorClass; +typedef struct _EContactListEditor EContactListEditor; +typedef struct _EContactListEditorClass EContactListEditorClass; +typedef struct _EContactListEditorPrivate EContactListEditorPrivate; struct _EContactListEditor { EABEditor parent; - - /* item specific fields */ - EBook *book; - - EContact *contact; - - GladeXML *gui; - GtkWidget *app; - - GtkWidget *table; - ETableModel *model; - GtkWidget *email_entry; - GtkWidget *list_name_entry; - GtkWidget *add_button; - GtkWidget *remove_button; - GtkWidget *select_button; - GtkWidget *list_image_button; - GtkWidget *visible_addrs_checkbutton; - GtkWidget *list_image; - GtkWidget *source_menu; - GtkWidget *ok_button; - GtkWidget *cancel_button; - - ENameSelector *name_selector; - - /* Whether we are editing a new contact or an existing one */ - guint is_new_list : 1; - - /* Whether the image chooser widget has been changed. */ - guint image_set : 1; - - /* 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; + EContactListEditorPrivate *priv; }; struct _EContactListEditorClass @@ -99,15 +67,31 @@ struct _EContactListEditorClass EABEditorClass parent_class; }; -EContactListEditor *e_contact_list_editor_new (EBook *book, - EContact *list_contact, - gboolean is_new_list, - gboolean editable); -GType e_contact_list_editor_get_type (void); - -gboolean e_contact_list_editor_request_close_all (void); +GType e_contact_list_editor_get_type (void); +EContactListEditor * e_contact_list_editor_new (EBook *book, + EContact *list_contact, + gboolean is_new_list, + gboolean editable); +EBook * e_contact_list_editor_get_book (EContactListEditor *editor); +void e_contact_list_editor_set_book (EContactListEditor *editor, + EBook *book); +EContact * e_contact_list_editor_get_contact + (EContactListEditor *editor); +void e_contact_list_editor_set_contact + (EContactListEditor *editor, + EContact *contact); +gboolean e_contact_list_editor_get_is_new_list + (EContactListEditor *editor); +void e_contact_list_editor_set_is_new_list + (EContactListEditor *editor, + gboolean is_new_list); +gboolean e_contact_list_editor_get_editable + (EContactListEditor *editor); +void e_contact_list_editor_set_editable + (EContactListEditor *editor, + gboolean editable); +gboolean e_contact_list_editor_request_close_all (void); G_END_DECLS - #endif /* __E_CONTACT_LIST_EDITOR_H__ */ diff --git a/addressbook/gui/contact-list-editor/e-contact-list-model.c b/addressbook/gui/contact-list-editor/e-contact-list-model.c index 767e461d87..d596919481 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-model.c +++ b/addressbook/gui/contact-list-editor/e-contact-list-model.c @@ -2,283 +2,198 @@ #include #include + #include "e-contact-list-model.h" #include "e-util/e-error.h" -#include -#define PARENT_TYPE e_table_model_get_type() -static ETableModelClass *parent_class; - -#define COLS 1 - -/* This function returns the number of columns in our ETableModel. */ -static int -contact_list_col_count (ETableModel *etc) -{ - return COLS; -} - -/* This function returns the number of rows in our ETableModel. */ -static int -contact_list_row_count (ETableModel *etc) -{ - EContactListModel *model = E_CONTACT_LIST_MODEL (etc); - return model->data_count; -} - -/* This function returns the value at a particular point in our ETableModel. */ -static void * -contact_list_value_at (ETableModel *etc, int col, int row) -{ - EContactListModel *model = E_CONTACT_LIST_MODEL (etc); - - return (void *) e_destination_get_textrep (model->data[row], TRUE); -} - -/* This function sets the value at a particular point in our ETableModel. */ -static void -contact_list_set_value_at (ETableModel *etc, int col, int row, const void *val) -{ - /* nothing */ -} +static gpointer parent_class; -/* This function returns whether a particular cell is editable. */ static gboolean -contact_list_is_cell_editable (ETableModel *etc, int col, int row) +contact_list_get_iter (EContactListModel *model, + GtkTreeIter *iter, + gint row) { - return FALSE; -} - -/* This function duplicates the value passed to it. */ -static void * -contact_list_duplicate_value (ETableModel *etc, int col, const void *value) -{ - return g_strdup(value); -} + GtkTreePath *path; + gboolean iter_valid; -/* This function frees the value passed to it. */ -static void -contact_list_free_value (ETableModel *etc, int col, void *value) -{ - g_free(value); -} + path = gtk_tree_path_new_from_indices (row, -1); + iter_valid = gtk_tree_model_get_iter ( + GTK_TREE_MODEL (model), iter, path); + gtk_tree_path_free (path); -static void * -contact_list_initialize_value (ETableModel *etc, int col) -{ - return g_strdup(""); + return iter_valid; } -static gboolean -contact_list_value_is_empty (ETableModel *etc, int col, const void *value) +static GObject * +contact_list_model_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) { - return !(value && *(char *)value); -} + GObject *object; + GType types[1]; -static char * -contact_list_value_to_string (ETableModel *etc, int col, const void *value) -{ - return g_strdup(value); -} + types[0] = E_TYPE_DESTINATION; -static void -contact_list_model_dispose (GObject *o) -{ - EContactListModel *model = E_CONTACT_LIST_MODEL (o); - int i; - - if (model->data != NULL) { - for (i = 0; i < model->data_count; i ++) { - g_object_unref (model->data[i]); - } - g_free (model->data); - model->data = NULL; - } + /* Chain up to parent's constructor() method. */ + object = G_OBJECT_CLASS (parent_class)->constructor ( + type, n_construct_properties, construct_properties); - model->data_count = 0; - model->data_alloc = 0; + gtk_list_store_set_column_types ( + GTK_LIST_STORE (object), G_N_ELEMENTS (types), types); - (* G_OBJECT_CLASS (parent_class)->dispose) (o); + return object; } static void -e_contact_list_model_class_init (GObjectClass *object_class) +contact_list_model_class_init (EContactListModelClass *class) { - ETableModelClass *model_class = (ETableModelClass *) object_class; - - parent_class = g_type_class_ref (PARENT_TYPE); - - object_class->dispose = contact_list_model_dispose; - - model_class->column_count = contact_list_col_count; - model_class->row_count = contact_list_row_count; - model_class->value_at = contact_list_value_at; - model_class->set_value_at = contact_list_set_value_at; - model_class->is_cell_editable = contact_list_is_cell_editable; - model_class->duplicate_value = contact_list_duplicate_value; - model_class->free_value = contact_list_free_value; - model_class->initialize_value = contact_list_initialize_value; - model_class->value_is_empty = contact_list_value_is_empty; - model_class->value_to_string = contact_list_value_to_string; -} + GObjectClass *object_class; -static void -e_contact_list_model_init (GObject *object) -{ - EContactListModel *model = E_CONTACT_LIST_MODEL(object); + parent_class = g_type_class_peek_parent (class); - model->data_alloc = 10; - model->data_count = 0; - model->data = g_new (EDestination*, model->data_alloc); + object_class = G_OBJECT_CLASS (class); + object_class->constructor = contact_list_model_constructor; } GType e_contact_list_model_get_type (void) { - static GType cle_type = 0; + static GType type = 0; - if (!cle_type) { - static const GTypeInfo cle_info = { + if (G_UNLIKELY (type == 0)) + type = g_type_register_static_simple ( + GTK_TYPE_LIST_STORE, + "EContactListModel", sizeof (EContactListModelClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_contact_list_model_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ + (GClassInitFunc) contact_list_model_class_init, sizeof (EContactListModel), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_contact_list_model_init, - }; - - cle_type = g_type_register_static (E_TABLE_MODEL_TYPE, "EContactListModel", &cle_info, 0); - } + (GInstanceInitFunc) NULL, 0); - return cle_type; + return type; } -void -e_contact_list_model_construct (EContactListModel *model) +GtkTreeModel * +e_contact_list_model_new (void) { + return g_object_new (E_TYPE_CONTACT_LIST_MODEL, NULL); } -ETableModel * -e_contact_list_model_new (void) +gboolean +e_contact_list_model_has_email (EContactListModel *model, + const gchar *email) { - EContactListModel *model; + GtkTreeIter iter; + gboolean iter_valid; + gboolean has_email = FALSE; + + g_return_val_if_fail (E_IS_CONTACT_LIST_MODEL (model), FALSE); + g_return_val_if_fail (email != NULL, FALSE); - model = g_object_new (E_TYPE_CONTACT_LIST_MODEL, NULL); + iter_valid = gtk_tree_model_get_iter_first ( + GTK_TREE_MODEL (model), &iter); - e_contact_list_model_construct (model); + while (!has_email && iter_valid) { + EDestination *destination; + const gchar *textrep; - return E_TABLE_MODEL(model); + gtk_tree_model_get ( + GTK_TREE_MODEL (model), &iter, 0, &destination, -1); + textrep = e_destination_get_textrep (destination, TRUE); + has_email = (strcmp (email, textrep) == 0); + g_object_unref (destination); + + iter_valid = gtk_tree_model_iter_next ( + GTK_TREE_MODEL (model), &iter); + } + + return has_email; } void -e_contact_list_model_add_destination (EContactListModel *model, EDestination *dest) +e_contact_list_model_add_destination (EContactListModel *model, + EDestination *destination) { - g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); - g_return_if_fail (E_IS_DESTINATION (dest)); + GtkTreeIter iter; - e_table_model_pre_change (E_TABLE_MODEL (model)); - - if (model->data_count + 1 >= model->data_alloc) { - model->data_alloc *= 2; - model->data = g_renew (EDestination*, model->data, model->data_alloc); - } - - model->data[model->data_count ++] = dest; - g_object_ref (dest); + g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); + g_return_if_fail (E_IS_DESTINATION (destination)); - e_table_model_row_inserted (E_TABLE_MODEL (model), model->data_count - 1); + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, destination, -1); } void e_contact_list_model_add_email (EContactListModel *model, - const char *email) + const gchar *email) { - EDestination *new_dest; - char *list_email; - int row; - int row_count; + const gchar *tag = "addressbook:ask-list-add-exists"; + EDestination *destination; g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); g_return_if_fail (email != NULL); - row_count = e_table_model_row_count (E_TABLE_MODEL (model)); + if (e_contact_list_model_has_email (model, email)) + if (e_error_run (NULL, tag, email) != GTK_RESPONSE_YES) + return; - for (row = 0; row < row_count; row++) { - list_email = (char *) e_table_model_value_at (E_TABLE_MODEL (model), 1, row); - - if (strcmp (list_email, email) == 0) { - if (e_error_run (NULL, "addressbook:ask-list-add-exists", - email) != GTK_RESPONSE_YES) - return; - break; - } - } - - new_dest = e_destination_new (); - e_destination_set_email (new_dest, email); - - e_contact_list_model_add_destination (model, new_dest); + destination = e_destination_new (); + e_destination_set_email (destination, email); + e_contact_list_model_add_destination (model, destination); } void e_contact_list_model_add_contact (EContactListModel *model, - EContact *contact, - int email_num) + EContact *contact, + gint email_num) { - EDestination *new_dest; + EDestination *destination; g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); g_return_if_fail (E_IS_CONTACT (contact)); - new_dest = e_destination_new (); - e_destination_set_contact (new_dest, contact, email_num); - - e_contact_list_model_add_destination (model, new_dest); + destination = e_destination_new (); + e_destination_set_contact (destination, contact, email_num); + e_contact_list_model_add_destination (model, destination); } void -e_contact_list_model_remove_row (EContactListModel *model, int row) +e_contact_list_model_remove_row (EContactListModel *model, + gint row) { - g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); - g_return_if_fail (0 <= row && row < model->data_count); + GtkTreeIter iter; + gboolean iter_valid; - e_table_model_pre_change (E_TABLE_MODEL (model)); + g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); - g_object_unref (model->data[row]); - memmove (model->data + row, model->data + row + 1, sizeof (EDestination*) * (model->data_count - row - 1)); - model->data_count --; + iter_valid = contact_list_get_iter (model, &iter, row); + g_return_if_fail (iter_valid); - e_table_model_row_deleted (E_TABLE_MODEL (model), row); + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } void e_contact_list_model_remove_all (EContactListModel *model) { - int i; - g_return_if_fail (E_IS_CONTACT_LIST_MODEL (model)); - e_table_model_pre_change (E_TABLE_MODEL (model)); - - for (i = 0; i < model->data_count; i ++) { - g_object_unref (model->data[i]); - model->data[i] = NULL; - } - - model->data_count = 0; - - e_table_model_changed (E_TABLE_MODEL (model)); + gtk_list_store_clear (GTK_LIST_STORE (model)); } - -const EDestination * -e_contact_list_model_get_destination (EContactListModel *model, int row) +EDestination * +e_contact_list_model_get_destination (EContactListModel *model, + gint row) { + EDestination *destination; + GtkTreeIter iter; + gboolean iter_valid; + g_return_val_if_fail (E_IS_CONTACT_LIST_MODEL (model), NULL); - g_return_val_if_fail (0 <= row && row < model->data_count, NULL); - return model->data[row]; + iter_valid = contact_list_get_iter (model, &iter, row); + g_return_val_if_fail (iter_valid, NULL); + + gtk_tree_model_get ( + GTK_TREE_MODEL (model), &iter, 0, &destination, -1); + + return destination; } diff --git a/addressbook/gui/contact-list-editor/e-contact-list-model.h b/addressbook/gui/contact-list-editor/e-contact-list-model.h index 55fe251ad2..68de720286 100644 --- a/addressbook/gui/contact-list-editor/e-contact-list-model.h +++ b/addressbook/gui/contact-list-editor/e-contact-list-model.h @@ -1,48 +1,62 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + #ifndef _E_CONTACT_LIST_MODEL_H_ #define _E_CONTACT_LIST_MODEL_H_ -#include
+#include #include #include -G_BEGIN_DECLS +/* Standard GObject macros */ +#define E_TYPE_CONTACT_LIST_MODEL \ + (e_contact_list_model_get_type ()) +#define E_CONTACT_LIST_MODEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_CONTACT_LIST_MODEL, EContactListModel)) +#define E_CONTACT_LIST_MODEL_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_CONTACT_LIST_MODEL, EContactListModelClass)) +#define E_IS_CONTACT_LIST_MODEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_CONTACT_LIST_MODEL)) +#define E_IS_CONTACT_LIST_MODEL_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_CONTACT_LIST_MODEL)) +#define E_CONTACT_LIST_MODEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_CONTACT_LIST_MODEL, EContactListModelClass)) -#define E_TYPE_CONTACT_LIST_MODEL (e_contact_list_model_get_type ()) -#define E_CONTACT_LIST_MODEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_CONTACT_LIST_MODEL, EContactListModel)) -#define E_CONTACT_LIST_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_CONTACT_LIST_MODEL, EContactListModelClass)) -#define E_IS_CONTACT_LIST_MODEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CONTACT_LIST_MODEL)) -#define E_IS_CONTACT_LIST_MODEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CONTACT_LIST_MODEL)) +G_BEGIN_DECLS typedef struct _EContactListModel EContactListModel; typedef struct _EContactListModelClass EContactListModelClass; struct _EContactListModel { - ETableModel parent; - - EDestination **data; - int data_count; - int data_alloc; + GtkListStore parent; }; - struct _EContactListModelClass { - ETableModelClass parent_class; + GtkListStoreClass parent_class; }; - -GType e_contact_list_model_get_type (void); -void e_contact_list_model_construct (EContactListModel *model); -ETableModel *e_contact_list_model_new (void); - -void e_contact_list_model_add_destination (EContactListModel *model, EDestination *dest); -void e_contact_list_model_add_email (EContactListModel *model, const char *email); -void e_contact_list_model_add_contact (EContactListModel *model, EContact *contact, int email_num); - -void e_contact_list_model_remove_row (EContactListModel *model, int row); -void e_contact_list_model_remove_all (EContactListModel *model); - -const EDestination *e_contact_list_model_get_destination (EContactListModel *model, int row); +GType e_contact_list_model_get_type (void); +GtkTreeModel * e_contact_list_model_new (void); +gboolean e_contact_list_model_has_email (EContactListModel *model, + const gchar *email); +void e_contact_list_model_add_destination + (EContactListModel *model, + EDestination *dest); +void e_contact_list_model_add_email (EContactListModel *model, + const gchar *email); +void e_contact_list_model_add_contact(EContactListModel *model, + EContact *contact, + gint email_num); +void e_contact_list_model_remove_row (EContactListModel *model, + gint row); +void e_contact_list_model_remove_all (EContactListModel *model); +EDestination * e_contact_list_model_get_destination + (EContactListModel *model, + gint row); G_END_DECLS -- cgit v1.2.3