From a3b92fe138eeacdbd24e8292c9ccc615bf8e949b Mon Sep 17 00:00:00 2001 From: Jon Trowbridge Date: Fri, 7 Dec 2001 16:43:44 +0000 Subject: Extensively refactored -- this code had gotten _really_ ugly. Untangle 2001-12-07 Jon Trowbridge * gui/component/select-names/e-select-names-manager.c: Extensively refactored -- this code had gotten _really_ ugly. Untangle things to the point where our reference counting problems are fixable. * gui/component/select-names/e-select-names-bonobo.c (impl_destroy): Remove all of the ugly hacks to work around our memory management problems, and just unref the manager. (Fixes #14412) svn path=/trunk/; revision=14934 --- addressbook/ChangeLog | 11 + .../component/select-names/e-select-names-bonobo.c | 19 +- .../select-names/e-select-names-manager.c | 814 +++++++++++---------- .../select-names/e-select-names-manager.h | 8 +- .../gui/component/select-names/e-select-names.c | 2 +- 5 files changed, 433 insertions(+), 421 deletions(-) (limited to 'addressbook') diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index 44cb5e44d7..39de1ee629 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,14 @@ +2001-12-07 Jon Trowbridge + + * gui/component/select-names/e-select-names-manager.c: Extensively + refactored -- this code had gotten _really_ ugly. Untangle things + to the point where our reference counting problems are fixable. + + * gui/component/select-names/e-select-names-bonobo.c + (impl_destroy): Remove all of the ugly hacks to work around our + memory management problems, and just unref the manager. + (Fixes #14412) + 2001-12-05 Chris Toshok * backend/pas/pas-backend-ldap.c diff --git a/addressbook/gui/component/select-names/e-select-names-bonobo.c b/addressbook/gui/component/select-names/e-select-names-bonobo.c index 071b2e0b2b..55ef3ec89a 100644 --- a/addressbook/gui/component/select-names/e-select-names-bonobo.c +++ b/addressbook/gui/component/select-names/e-select-names-bonobo.c @@ -348,18 +348,11 @@ impl_SelectNames_activate_dialog (PortableServer_Servant servant, /* GtkObject methods. */ -/* ACK! */ -typedef struct { - char *id; - EEntry *entry; -} ESelectNamesManagerEntry; - static void impl_destroy (GtkObject *object) { ESelectNamesBonobo *select_names; ESelectNamesBonoboPrivate *priv; - EIterator *iterator; select_names = E_SELECT_NAMES_BONOBO (object); priv = select_names->priv; @@ -369,17 +362,7 @@ impl_destroy (GtkObject *object) priv->manager->names = NULL; } - /* More suckage */ - iterator = e_list_get_iterator (priv->manager->entries); - for (e_iterator_reset (iterator); e_iterator_is_valid (iterator); e_iterator_next (iterator)) { - ESelectNamesManagerEntry *entry = (ESelectNamesManagerEntry *)e_iterator_get (iterator); - if (entry && entry->entry) - gtk_widget_destroy (GTK_WIDGET (entry->entry)); - } - gtk_object_unref (GTK_OBJECT (iterator)); - - /* FIXME: We leak on purpose. This sucks. */ - /* gtk_object_unref (GTK_OBJECT (priv->manager)); */ + gtk_object_unref (GTK_OBJECT (priv->manager)); g_free (priv); } diff --git a/addressbook/gui/component/select-names/e-select-names-manager.c b/addressbook/gui/component/select-names/e-select-names-manager.c index e2b0238123..1a7dae4a74 100644 --- a/addressbook/gui/component/select-names/e-select-names-manager.c +++ b/addressbook/gui/component/select-names/e-select-names-manager.c @@ -2,8 +2,9 @@ /* * Authors: * Chris Lahey + * Jon Trowbridge @@ -26,15 +27,10 @@ #include #include -/* Object argument IDs */ -enum { - ARG_0, - ARG_CARD, -}; - enum { CHANGED, OK, + CANCEL, LAST_SIGNAL }; @@ -47,489 +43,411 @@ typedef struct { ESelectNamesModel *model; ESelectNamesModel *original_model; ESelectNamesManager *manager; - guint changed_handler; + guint changed_tag; } ESelectNamesManagerSection; typedef struct { char *id; EEntry *entry; + ESelectNamesManager *manager; + ESelectNamesModel *model; } ESelectNamesManagerEntry; static void e_select_names_manager_init (ESelectNamesManager *manager); static void e_select_names_manager_class_init (ESelectNamesManagerClass *klass); static void e_select_names_manager_destroy (GtkObject *object); -static void e_select_names_manager_set_arg (GtkObject *object, GtkArg *arg, guint arg_id); -static void e_select_names_manager_get_arg (GtkObject *object, GtkArg *arg, guint arg_id); -/** - * e_select_names_manager_get_type: - * @void: - * - * Registers the &ESelectNamesManager class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the &ESelectNamesManager class. - **/ -GtkType -e_select_names_manager_get_type (void) -{ - static GtkType manager_type = 0; +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ - if (!manager_type) { - GtkTypeInfo manager_info = { - "ESelectNamesManager", - sizeof (ESelectNamesManager), - sizeof (ESelectNamesManagerClass), - (GtkClassInitFunc) e_select_names_manager_class_init, - (GtkObjectInitFunc) e_select_names_manager_init, - NULL, /* reserved_1 */ - NULL, /* reserved_2 */ - (GtkClassInitFunc) NULL - }; - - manager_type = gtk_type_unique (gtk_object_get_type (), &manager_info); - } - - return manager_type; -} +/* ESelectNamesManagerSection routines */ static void -open_book_cb (EBook *book, EBookStatus status, ESelectNamesManager *manager) +section_model_changed_cb (ESelectNamesModel *model, gpointer closure) { - if (status != E_BOOK_STATUS_SUCCESS) { - gtk_object_unref (GTK_OBJECT (book)); - manager->completion_book = NULL; - } - - gtk_object_unref (GTK_OBJECT (manager)); /* unref ourself (matches ref before the load_uri call below) */ + ESelectNamesManagerSection *section = closure; + gtk_signal_emit (GTK_OBJECT (section->manager), + e_select_names_manager_signals[CHANGED], + section->id, + FALSE); } -/** - * e_select_names_manager_new: - * @VCard: a string in vCard format - * - * Returns: a new #ESelectNamesManager that wraps the @VCard. - */ -ESelectNamesManager * -e_select_names_manager_new (void) +static ESelectNamesManagerSection * +e_select_names_manager_section_new (ESelectNamesManager *manager, + const gchar *id, + const gchar *title, + ESelectNamesModel *model) { - ESelectNamesManager *manager = E_SELECT_NAMES_MANAGER(gtk_type_new(e_select_names_manager_get_type())); - Bonobo_ConfigDatabase db; - CORBA_Environment ev; - char *val; + ESelectNamesManagerSection *section; - CORBA_exception_init (&ev); + g_return_val_if_fail (E_IS_SELECT_NAMES_MANAGER (manager), NULL); + g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), NULL); - db = addressbook_config_database (&ev); + section = g_new0 (ESelectNamesManagerSection, 1); - val = bonobo_config_get_string (db, "/Addressbook/Completion/uri", &ev); + section->id = g_strdup (id); + section->title = g_strdup (title); - CORBA_exception_free (&ev); + section->manager = manager; - if (val) { - manager->completion_book = e_book_new (); - gtk_object_ref (GTK_OBJECT (manager)); /* ref ourself before our async call */ - addressbook_load_uri (manager->completion_book, val, (EBookCallback)open_book_cb, manager); - g_free (val); - } - else - manager->completion_book = NULL; + section->model = model; + gtk_object_ref (GTK_OBJECT (section->model)); + section->changed_tag = + gtk_signal_connect (GTK_OBJECT (section->model), + "changed", + GTK_SIGNAL_FUNC (section_model_changed_cb), + section); - return manager; + return section; } static void -e_select_names_manager_class_init (ESelectNamesManagerClass *klass) +e_select_names_manager_section_free (ESelectNamesManagerSection *section) { - GtkObjectClass *object_class; - - object_class = GTK_OBJECT_CLASS(klass); - - gtk_object_add_arg_type ("ESelectNamesManager::card", - GTK_TYPE_OBJECT, GTK_ARG_READWRITE, ARG_CARD); + if (section == NULL) + return; - object_class->destroy = e_select_names_manager_destroy; - object_class->get_arg = e_select_names_manager_get_arg; - object_class->set_arg = e_select_names_manager_set_arg; + g_free (section->id); + g_free (section->title); - e_select_names_manager_signals[CHANGED] = - gtk_signal_new ("changed", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ESelectNamesManagerClass, changed), - gtk_marshal_NONE__POINTER_INT, - GTK_TYPE_NONE, 2, - GTK_TYPE_POINTER, - GTK_TYPE_INT); + if (section->model) { + gtk_signal_disconnect (GTK_OBJECT (section->model), section->changed_tag); + gtk_object_unref (GTK_OBJECT (section->model)); + } - e_select_names_manager_signals[OK] = - gtk_signal_new ("ok", - GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (ESelectNamesManagerClass, ok), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); + if (section->original_model) { + gtk_object_unref (GTK_OBJECT (section->original_model)); + } - gtk_object_class_add_signals (object_class, e_select_names_manager_signals, LAST_SIGNAL); + g_free (section); } -/* - * ESelectNamesManager lifecycle management and vcard loading/saving. - */ - -static void -e_select_names_manager_destroy (GtkObject *object) -{ - ESelectNamesManager *manager; - - manager = E_SELECT_NAMES_MANAGER (object); +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ - gtk_object_unref(GTK_OBJECT(manager->sections)); - gtk_object_unref(GTK_OBJECT(manager->entries)); +/* ESelectNamesManagerEntry routines */ - if (manager->names) { - gtk_widget_destroy (GTK_WIDGET (manager->names)); - manager->names = NULL; - } +static ESelectNamesManagerEntry * +get_entry_info (EEntry *entry) +{ + g_return_val_if_fail (E_IS_ENTRY (entry), NULL); + return (ESelectNamesManagerEntry *) gtk_object_get_data (GTK_OBJECT (entry), "entry_info"); } - -/* Set_arg handler for the manager */ static void -e_select_names_manager_set_arg (GtkObject *object, GtkArg *arg, guint arg_id) +popup_cb (EEntry *eentry, GdkEventButton *ev, gint pos, gpointer user_data) { - ESelectNamesManager *manager; - - manager = E_SELECT_NAMES_MANAGER (object); + ESelectNamesManagerEntry *entry = user_data; - switch (arg_id) { - case ARG_CARD: - break; - default: - return; - } + e_select_names_popup (entry->model, ev, pos); } -/* Get_arg handler for the manager */ -static void -e_select_names_manager_get_arg (GtkObject *object, GtkArg *arg, guint arg_id) +static gint +focus_in_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) { - ESelectNamesManager *manager; + ESelectNamesManagerEntry *entry = user_data; - manager = E_SELECT_NAMES_MANAGER (object); + e_select_names_model_cancel_cardify_all (entry->model); - switch (arg_id) { - case ARG_CARD: - break; - default: - arg->type = GTK_TYPE_INVALID; - break; - } + return FALSE; } -static void * -section_copy(const void *sec, void *data) +static gint +focus_out_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) { - const ESelectNamesManagerSection *section = sec; - ESelectNamesManagerSection *newsec; - - static void section_model_changed_cb (ESelectNamesModel *, gpointer); - - newsec = g_new(ESelectNamesManagerSection, 1); - newsec->id = g_strdup(section->id); - newsec->title = g_strdup(section->title); - newsec->model = section->model; - newsec->original_model = section->original_model; - newsec->manager = section->manager; - newsec->changed_handler = gtk_signal_connect (GTK_OBJECT (newsec->model), - "changed", - GTK_SIGNAL_FUNC (section_model_changed_cb), - newsec); - - if (newsec->model) - gtk_object_ref(GTK_OBJECT(newsec->model)); - if (newsec->original_model) - gtk_object_ref(GTK_OBJECT(newsec->original_model)); - - return newsec; -} + ESelectNamesManagerEntry *entry = user_data; -static void -section_free(void *sec, void *data) -{ - ESelectNamesManagerSection *section = sec; - if (section->manager && section->changed_handler) { - gtk_signal_disconnect (GTK_OBJECT (section->model), section->changed_handler); - } - g_free(section->id); - g_free(section->title); - if (section->model) - gtk_object_unref (GTK_OBJECT(section->model)); - if (section->original_model) - gtk_object_unref (GTK_OBJECT (section->original_model)); + e_select_names_model_clean (entry->model); - g_free(section); -} + if (!e_entry_completion_popup_is_visible (entry->entry)) + e_select_names_model_cardify_all (entry->model, entry->manager->completion_book, 100); -static void * -entry_copy(const void *ent, void *data) -{ - const ESelectNamesManagerEntry *entry = ent; - ESelectNamesManagerEntry *newent; - - newent = g_new(ESelectNamesManagerEntry, 1); - newent->id = g_strdup(entry->id); - newent->entry = entry->entry; - if (newent->entry) - gtk_object_ref(GTK_OBJECT(newent->entry)); - return newent; + return FALSE; } static void -entry_free(void *ent, void *data) +completion_popup_cb (EEntry *w, gint visible, gpointer user_data) { - ESelectNamesManagerEntry *entry = ent; - g_free(entry->id); - if (entry->entry) - gtk_object_unref(GTK_OBJECT(entry->entry)); - g_free(entry); -} + ESelectNamesManagerEntry *entry = user_data; -/** - * e_select_names_manager_init: - */ -static void -e_select_names_manager_init (ESelectNamesManager *manager) -{ - manager->sections = e_list_new(section_copy, section_free, manager); - manager->entries = e_list_new(entry_copy, entry_free, manager); + if (!visible && !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry->entry->canvas))) + e_select_names_model_cardify_all (entry->model, entry->manager->completion_book, 0); } static void -section_model_changed_cb (ESelectNamesModel *model, gpointer closure) +completion_handler (EEntry *entry, ECompletionMatch *match) { - ESelectNamesManagerSection *section = closure; - gtk_signal_emit (GTK_OBJECT (section->manager), - e_select_names_manager_signals[CHANGED], - section->id, - FALSE); -} + ESelectNamesManagerEntry *mgr_entry; + EDestination *dest; + gint i, pos, start_pos, len; -static void -section_model_working_copy_changed_cb (ESelectNamesModel *model, gpointer closure) -{ - ESelectNamesManagerSection *section = closure; - gtk_signal_emit (GTK_OBJECT (section->manager), - e_select_names_manager_signals[CHANGED], - section->id, - TRUE); -} + if (match == NULL || match->user_data == NULL) + return; -void -e_select_names_manager_add_section (ESelectNamesManager *manager, - const char *id, - const char *title) -{ - e_select_names_manager_add_section_with_limit (manager, id, title, -1); + mgr_entry = get_entry_info (entry); + dest = E_DESTINATION (match->user_data); + + /* Sometimes I really long for garbage collection. Reference + counting makes you feel 31337, but sometimes it is just a + bitch. */ + gtk_object_ref (GTK_OBJECT (dest)); + + pos = e_entry_get_position (entry); + e_select_names_model_text_pos (mgr_entry->model, pos, &i, NULL, NULL); + e_select_names_model_replace (mgr_entry->model, i, dest); + e_select_names_model_name_pos (mgr_entry->model, i, &start_pos, &len); + e_entry_set_position (entry, start_pos+len); } -void -e_select_names_manager_add_section_with_limit (ESelectNamesManager *manager, - const char *id, - const char *title, - gint limit) +static ESelectNamesManagerEntry * +e_select_names_manager_entry_new (ESelectNamesManager *manager, ESelectNamesModel *model, const gchar *id) { - ESelectNamesManagerSection *section; + ESelectNamesManagerEntry *entry; + ETextModel *text_model; + ECompletion *comp; + + g_return_val_if_fail (E_IS_SELECT_NAMES_MANAGER (manager), NULL); + g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), NULL); + + entry = g_new0 (ESelectNamesManagerEntry, 1); + + entry->id = g_strdup (id); + + entry->entry = E_ENTRY (e_entry_new ()); + text_model = e_select_names_text_model_new (model); + gtk_object_set(GTK_OBJECT(entry->entry), + "model", text_model, /* The entry takes ownership of the text model */ + "editable", TRUE, + "use_ellipsis", TRUE, + "allow_newlines", FALSE, + NULL); + + gtk_object_ref (GTK_OBJECT (entry->entry)); + + comp = e_select_names_completion_new (NULL, model); + if (manager->completion_book) + e_select_names_completion_add_book (E_SELECT_NAMES_COMPLETION (comp), + manager->completion_book); + e_select_names_completion_add_destination_cache (E_SELECT_NAMES_COMPLETION (comp), + addressbook_destination_cache ()); + + e_entry_enable_completion_full (entry->entry, comp, 50, completion_handler); + + entry->manager = manager; + + entry->model = model; + gtk_object_ref (GTK_OBJECT (model)); - section = g_new(ESelectNamesManagerSection, 1); - section->id = g_strdup(id); - section->title = g_strdup(title); + gtk_signal_connect (GTK_OBJECT (entry->entry), + "popup", + GTK_SIGNAL_FUNC (popup_cb), + entry); + + gtk_signal_connect (GTK_OBJECT (entry->entry->canvas), + "focus_in_event", + GTK_SIGNAL_FUNC (focus_in_cb), + entry); + + gtk_signal_connect (GTK_OBJECT (entry->entry->canvas), + "focus_out_event", + GTK_SIGNAL_FUNC (focus_out_cb), + entry); - section->model = e_select_names_model_new(); - e_select_names_model_set_limit (section->model, limit); + gtk_signal_connect (GTK_OBJECT (entry->entry), + "completion_popup", + GTK_SIGNAL_FUNC (completion_popup_cb), + entry); - section->original_model = NULL; + gtk_object_set_data (GTK_OBJECT (entry->entry), "entry_info", entry); + gtk_object_set_data (GTK_OBJECT (entry->entry), "select_names_model", model); + gtk_object_set_data (GTK_OBJECT (entry->entry), "completion_handler", comp); - section->manager = manager; + return entry; +} - section->changed_handler = gtk_signal_connect (GTK_OBJECT (section->model), - "changed", - GTK_SIGNAL_FUNC (section_model_changed_cb), - section); +static void +e_select_names_manager_entry_free (ESelectNamesManagerEntry *entry) +{ + if (entry == NULL) + return; - e_list_append(manager->sections, section); - section_free(section, manager); + g_free (entry->id); + gtk_object_unref (GTK_OBJECT (entry->model)); + gtk_object_unref (GTK_OBJECT (entry->entry)); + + g_free (entry); } -ESelectNamesModel * -e_select_names_manager_get_source (ESelectNamesManager *manager, const char *id) +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ + +static void +e_select_names_manager_save_models (ESelectNamesManager *manager) { - EIterator *iterator; + GList *iter; + + for (iter = manager->sections; iter != NULL; iter = g_list_next (iter)) { + ESelectNamesManagerSection *section = iter->data; - g_return_val_if_fail (manager && E_IS_SELECT_NAMES_MANAGER (manager), NULL); - g_return_val_if_fail (id, NULL); + if (section->original_model == NULL && section->model != NULL) + section->original_model = e_select_names_model_duplicate (section->model); - iterator = e_list_get_iterator (manager->sections); - for (e_iterator_reset (iterator); e_iterator_is_valid (iterator); e_iterator_next (iterator)) { - const ESelectNamesManagerSection *section = e_iterator_get (iterator); - if (!strcmp (section->id, id)) { - return section->model; - } } - - return NULL; } static void -entry_destroyed(EEntry *entry, ESelectNamesManager *manager) +e_select_names_manager_revert_to_saved_models (ESelectNamesManager *manager) { - if(!GTK_OBJECT_DESTROYED(manager)) { - EIterator *iterator = e_list_get_iterator(manager->entries); - for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ESelectNamesManagerEntry *this_entry = e_iterator_get(iterator); - if(entry == this_entry->entry) { - e_iterator_delete(iterator); - break; - } + GList *iter; + + for (iter = manager->sections; iter != NULL; iter = g_list_next (iter)) { + ESelectNamesManagerSection *section = iter->data; + if (section->model && section->original_model) { + e_select_names_model_overwrite_copy (section->model, section->original_model); + gtk_object_unref (GTK_OBJECT (section->original_model)); + section->original_model = NULL; } } } static void -completion_handler (EEntry *entry, ECompletionMatch *match) +e_select_names_manager_discard_saved_models (ESelectNamesManager *manager) { - ESelectNamesModel *snm; - EDestination *dest; - gint i, pos, start_pos, len; + GList *iter; - if (match == NULL || match->user_data == NULL) - return; + for (iter = manager->sections; iter != NULL; iter = g_list_next (iter)) { + ESelectNamesManagerSection *section = iter->data; + if (section->original_model) { + gtk_object_unref (GTK_OBJECT (section->original_model)); + section->original_model = NULL; + } + } +} +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ - snm = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model")); - dest = E_DESTINATION (match->user_data); - /* Sometimes I really long for garbage collection. Reference - counting makes you feel 31337, but sometimes it is just a - bitch. */ - gtk_object_ref (GTK_OBJECT (dest)); +static void +open_book_cb (EBook *book, EBookStatus status, ESelectNamesManager *manager) +{ + if (status != E_BOOK_STATUS_SUCCESS) { + gtk_object_unref (GTK_OBJECT (book)); + manager->completion_book = NULL; + } - pos = e_entry_get_position (entry); - e_select_names_model_text_pos (snm, pos, &i, NULL, NULL); - e_select_names_model_replace (snm, i, dest); - e_select_names_model_name_pos (snm, i, &start_pos, &len); - e_entry_set_position (entry, start_pos+len); + gtk_object_unref (GTK_OBJECT (manager)); /* unref ourself (matches ref before the load_uri call below) */ } -static void -popup_cb (EEntry *entry, GdkEventButton *ev, gint pos, ESelectNamesModel *model) +/** + * e_select_names_manager_new: + * @VCard: a string in vCard format + * + * Returns: a new #ESelectNamesManager that wraps the @VCard. + */ +ESelectNamesManager * +e_select_names_manager_new (void) { - e_select_names_popup (model, ev, pos); + ESelectNamesManager *manager = E_SELECT_NAMES_MANAGER(gtk_type_new(e_select_names_manager_get_type())); + Bonobo_ConfigDatabase db; + CORBA_Environment ev; + char *val; + + CORBA_exception_init (&ev); + + db = addressbook_config_database (&ev); + + val = bonobo_config_get_string (db, "/Addressbook/Completion/uri", &ev); + + CORBA_exception_free (&ev); + + if (val) { + manager->completion_book = e_book_new (); + gtk_object_ref (GTK_OBJECT (manager)); /* ref ourself before our async call */ + addressbook_load_uri (manager->completion_book, val, (EBookCallback)open_book_cb, manager); + g_free (val); + } + else + manager->completion_book = NULL; + + return manager; } -static gint -focus_in_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) -{ - EEntry *entry = E_ENTRY (user_data); - ESelectNamesModel *model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model")); - e_select_names_model_cancel_cardify_all (model); +/* + * ESelectNamesManager lifecycle management and vcard loading/saving. + */ - return FALSE; + +void +e_select_names_manager_add_section (ESelectNamesManager *manager, + const char *id, + const char *title) +{ + g_return_if_fail (E_IS_SELECT_NAMES_MANAGER (manager)); + g_return_if_fail (id != NULL); + g_return_if_fail (title != NULL); + + e_select_names_manager_add_section_with_limit (manager, id, title, -1); } -static gint -focus_out_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data) +void +e_select_names_manager_add_section_with_limit (ESelectNamesManager *manager, + const char *id, + const char *title, + gint limit) { - EEntry *entry = E_ENTRY (user_data); - ESelectNamesModel *model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model")); - ESelectNamesManager *manager = E_SELECT_NAMES_MANAGER (gtk_object_get_data (GTK_OBJECT (entry), "select_names_manager")); + ESelectNamesManagerSection *section; + ESelectNamesModel *model; - e_select_names_model_clean (model); + g_return_if_fail (E_IS_SELECT_NAMES_MANAGER (manager)); + g_return_if_fail (id != NULL); + g_return_if_fail (title != NULL); + + model = e_select_names_model_new (); + e_select_names_model_set_limit (model, limit); + + section = e_select_names_manager_section_new (manager, id, title, model); - if (!e_entry_completion_popup_is_visible (entry)) - e_select_names_model_cardify_all (model, manager->completion_book, 100); + manager->sections = g_list_append (manager->sections, section); - return FALSE; + gtk_object_unref (GTK_OBJECT (model)); } -static void -completion_popup_cb (EEntry *entry, gint visible, gpointer user_data) +ESelectNamesModel * +e_select_names_manager_get_source (ESelectNamesManager *manager, + const char *id) { - ESelectNamesModel *model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model")); - ESelectNamesManager *manager = E_SELECT_NAMES_MANAGER (gtk_object_get_data (GTK_OBJECT (entry), "select_names_manager")); + GList *iter; + + g_return_val_if_fail (E_IS_SELECT_NAMES_MANAGER (manager), NULL); + g_return_val_if_fail (id != NULL, NULL); - if (!visible && !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry->canvas))) - e_select_names_model_cardify_all (model, manager->completion_book, 0); + for (iter = manager->sections; iter != NULL; iter = g_list_next (iter)) { + ESelectNamesManagerSection *section = iter->data; + if (!strcmp (section->id, id)) + return section->model; + } + return NULL; } GtkWidget * e_select_names_manager_create_entry (ESelectNamesManager *manager, const char *id) { - ETextModel *model; - EIterator *iterator; - iterator = e_list_get_iterator(manager->sections); - for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - const ESelectNamesManagerSection *section = e_iterator_get(iterator); + GList *iter; + + g_return_val_if_fail (E_IS_SELECT_NAMES_MANAGER (manager), NULL); + g_return_val_if_fail (id != NULL, NULL); + + for (iter = manager->sections; iter != NULL; iter = g_list_next (iter)) { + ESelectNamesManagerSection *section = iter->data; if (!strcmp(section->id, id)) { ESelectNamesManagerEntry *entry; - EEntry *eentry; - ECompletion *comp; - eentry = E_ENTRY (e_entry_new ()); - gtk_object_set_data (GTK_OBJECT (eentry), "select_names_model", section->model); - gtk_object_set_data (GTK_OBJECT (eentry), "select_names_manager", manager); + entry = e_select_names_manager_entry_new (manager, section->model, section->id); + manager->entries = g_list_append (manager->entries, entry); - gtk_signal_connect (GTK_OBJECT (eentry), - "popup", - GTK_SIGNAL_FUNC (popup_cb), - section->model); - - gtk_signal_connect (GTK_OBJECT (eentry->canvas), - "focus_in_event", - GTK_SIGNAL_FUNC (focus_in_cb), - eentry); - gtk_signal_connect (GTK_OBJECT (eentry->canvas), - "focus_out_event", - GTK_SIGNAL_FUNC (focus_out_cb), - eentry); - gtk_signal_connect (GTK_OBJECT (eentry), - "completion_popup", - GTK_SIGNAL_FUNC (completion_popup_cb), - NULL); - - entry = g_new (ESelectNamesManagerEntry, 1); - entry->entry = eentry; - entry->id = (char *)id; - - gtk_object_ref (GTK_OBJECT (entry->entry)); - - model = e_select_names_text_model_new (section->model); - e_list_append (manager->entries, entry); - g_free(entry); - - comp = e_select_names_completion_new (NULL, section->model); - if (manager->completion_book) - e_select_names_completion_add_book (E_SELECT_NAMES_COMPLETION (comp), - manager->completion_book); - e_entry_enable_completion_full (eentry, comp, 50, completion_handler); - - gtk_object_set_data (GTK_OBJECT (eentry), "completion_handler", comp); - - gtk_object_set(GTK_OBJECT(eentry), - "model", model, - "editable", TRUE, - "use_ellipsis", TRUE, - "allow_newlines", FALSE, - NULL); - - gtk_signal_connect(GTK_OBJECT(eentry), "destroy", - GTK_SIGNAL_FUNC(entry_destroyed), manager); - - return GTK_WIDGET(eentry); + return GTK_WIDGET(entry->entry); } } + return NULL; } @@ -540,59 +458,159 @@ e_select_names_clicked(ESelectNames *dialog, gint button, ESelectNamesManager *m switch(button) { case 0: - /* We don't need to do much if they click on OK */ - + e_select_names_manager_discard_saved_models (manager); gtk_signal_emit (GTK_OBJECT (manager), e_select_names_manager_signals[OK]); break; - case 1: { - EList *list = manager->sections; - EIterator *iterator = e_list_get_iterator(list); - - for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - ESelectNamesManagerSection *section = (void *) e_iterator_get(iterator); - e_select_names_model_overwrite_copy (section->model, section->original_model); - } - - gtk_object_unref(GTK_OBJECT(iterator)); + case 1: + e_select_names_manager_revert_to_saved_models (manager); + gtk_signal_emit (GTK_OBJECT (manager), e_select_names_manager_signals[CANCEL]); break; } - } } void e_select_names_manager_activate_dialog (ESelectNamesManager *manager, const char *id) { - EIterator *iterator; - + g_return_if_fail (E_IS_SELECT_NAMES_MANAGER (manager)); + g_return_if_fail (id != NULL); + if (manager->names) { + g_assert (GTK_WIDGET_REALIZED (GTK_WIDGET (manager->names))); - e_select_names_set_default(manager->names, id); + e_select_names_set_default (manager->names, id); gdk_window_show (GTK_WIDGET (manager->names)->window); gdk_window_raise (GTK_WIDGET (manager->names)->window); + } else { + + GList *iter; + manager->names = E_SELECT_NAMES (e_select_names_new ()); - iterator = e_list_get_iterator(manager->sections); - for (e_iterator_reset(iterator); e_iterator_is_valid(iterator); e_iterator_next(iterator)) { - ESelectNamesManagerSection *section = (ESelectNamesManagerSection *) e_iterator_get(iterator); - if (section->original_model != NULL) - gtk_object_unref (GTK_OBJECT (section->original_model)); - section->original_model = e_select_names_model_duplicate (section->model); + for (iter = manager->sections; iter != NULL; iter = g_list_next (iter)) { + ESelectNamesManagerSection *section = iter->data; e_select_names_add_section (manager->names, section->id, section->title, section->model); - gtk_signal_connect (GTK_OBJECT (section->model), - "changed", - GTK_SIGNAL_FUNC (section_model_working_copy_changed_cb), - (gpointer)section); /* casting out const to avoid compiler warning */ } - e_select_names_set_default(manager->names, id); - gtk_signal_connect(GTK_OBJECT(manager->names), "clicked", - GTK_SIGNAL_FUNC(e_select_names_clicked), manager); - gtk_signal_connect(GTK_OBJECT(manager->names), "destroy", + + e_select_names_set_default (manager->names, id); + + gtk_signal_connect(GTK_OBJECT(manager->names), + "clicked", + GTK_SIGNAL_FUNC(e_select_names_clicked), + manager); + + gtk_signal_connect(GTK_OBJECT(manager->names), + "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &manager->names); + gtk_widget_show(GTK_WIDGET(manager->names)); } + + e_select_names_manager_save_models (manager); +} + +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ + +static void +e_select_names_manager_init (ESelectNamesManager *manager) +{ + manager->sections = NULL; + manager->entries = NULL; +} + +static void +e_select_names_manager_destroy (GtkObject *object) +{ + ESelectNamesManager *manager; + + manager = E_SELECT_NAMES_MANAGER (object); + + if (manager->names) { + gtk_widget_destroy (GTK_WIDGET (manager->names)); + manager->names = NULL; + } + + g_list_foreach (manager->sections, (GFunc) e_select_names_manager_section_free, NULL); + g_list_free (manager->sections); + manager->sections = NULL; + + g_list_foreach (manager->entries, (GFunc) e_select_names_manager_entry_free, NULL); + g_list_free (manager->entries); + manager->entries = NULL; +} + +static void +e_select_names_manager_class_init (ESelectNamesManagerClass *klass) +{ + GtkObjectClass *object_class; + + object_class = GTK_OBJECT_CLASS(klass); + + object_class->destroy = e_select_names_manager_destroy; + + e_select_names_manager_signals[CHANGED] = + gtk_signal_new ("changed", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ESelectNamesManagerClass, changed), + gtk_marshal_NONE__POINTER_INT, + GTK_TYPE_NONE, 2, + GTK_TYPE_POINTER, + GTK_TYPE_INT); + + e_select_names_manager_signals[OK] = + gtk_signal_new ("ok", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ESelectNamesManagerClass, ok), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + e_select_names_manager_signals[CANCEL] = + gtk_signal_new ("cancel", + GTK_RUN_LAST, + object_class->type, + GTK_SIGNAL_OFFSET (ESelectNamesManagerClass, cancel), + gtk_marshal_NONE__NONE, + GTK_TYPE_NONE, 0); + + gtk_object_class_add_signals (object_class, e_select_names_manager_signals, LAST_SIGNAL); +} + +/** + * e_select_names_manager_get_type: + * @void: + * + * Registers the &ESelectNamesManager class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the &ESelectNamesManager class. + **/ +GtkType +e_select_names_manager_get_type (void) +{ + static GtkType manager_type = 0; + + if (!manager_type) { + GtkTypeInfo manager_info = { + "ESelectNamesManager", + sizeof (ESelectNamesManager), + sizeof (ESelectNamesManagerClass), + (GtkClassInitFunc) e_select_names_manager_class_init, + (GtkObjectInitFunc) e_select_names_manager_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + manager_type = gtk_type_unique (gtk_object_get_type (), &manager_info); + } + + return manager_type; } + + diff --git a/addressbook/gui/component/select-names/e-select-names-manager.h b/addressbook/gui/component/select-names/e-select-names-manager.h index 1304a13a71..9fdad2c304 100644 --- a/addressbook/gui/component/select-names/e-select-names-manager.h +++ b/addressbook/gui/component/select-names/e-select-names-manager.h @@ -27,8 +27,8 @@ typedef struct _ESelectNamesManagerClass ESelectNamesManagerClass; struct _ESelectNamesManager { GtkObject object; - EList *sections; - EList *entries; + GList *sections; + GList *entries; ESelectNames *names; @@ -40,6 +40,7 @@ struct _ESelectNamesManagerClass { void (*changed) (ESelectNamesManager *, const gchar *section_id, gint changed_working_copy); void (*ok) (ESelectNamesManager *); + void (*cancel) (ESelectNamesManager *); }; ESelectNamesManager *e_select_names_manager_new (void); @@ -51,12 +52,11 @@ void e_select_names_manager_add_section_with_limit (ESelectNames const char *title, gint limit); ESelectNamesModel *e_select_names_manager_get_source (ESelectNamesManager *manager, - const char *id); + const char *id); GtkWidget *e_select_names_manager_create_entry (ESelectNamesManager *manager, const char *id); void e_select_names_manager_activate_dialog (ESelectNamesManager *manager, const char *id); - /* Standard Gtk function */ GtkType e_select_names_manager_get_type (void); diff --git a/addressbook/gui/component/select-names/e-select-names.c b/addressbook/gui/component/select-names/e-select-names.c index fe737bbce7..5d6baa26fa 100644 --- a/addressbook/gui/component/select-names/e-select-names.c +++ b/addressbook/gui/component/select-names/e-select-names.c @@ -847,7 +847,7 @@ e_select_names_add_section(ESelectNames *e_select_names, char *name, char *id, E e_select_names->child_count + 1, GTK_FILL, GTK_FILL, 0, 0); - + model = e_select_names_table_model_new(source); etable = e_table_scrolled_new (model, NULL, SPEC2, NULL); -- cgit v1.2.3