Extensively refactored -- this code had gotten _really_ ugly. Untangle
2001-12-07 Jon Trowbridge <trow@ximian.com> * 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
This commit is contained in:

committed by
Jon Trowbridge

parent
3be029c79a
commit
a3b92fe138
@ -1,3 +1,14 @@
|
||||
2001-12-07 Jon Trowbridge <trow@ximian.com>
|
||||
|
||||
* 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 <toshok@ximian.com>
|
||||
|
||||
* backend/pas/pas-backend-ldap.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);
|
||||
}
|
||||
|
@ -2,8 +2,9 @@
|
||||
/*
|
||||
* Authors:
|
||||
* Chris Lahey <clahey@ximian.com>
|
||||
* Jon Trowbridge <trow@ximian.com.
|
||||
*
|
||||
* Copyright (C) 2000 Ximian, Inc.
|
||||
* Copyright (C) 2000, 2001 Ximian, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@ -26,15 +27,10 @@
|
||||
#include <bonobo/bonobo-object.h>
|
||||
#include <bonobo/bonobo-moniker-util.h>
|
||||
|
||||
/* Object argument IDs */
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_CARD,
|
||||
};
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
OK,
|
||||
CANCEL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -47,53 +43,288 @@ 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)
|
||||
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
|
||||
|
||||
/* ESelectNamesManagerSection routines */
|
||||
|
||||
static void
|
||||
section_model_changed_cb (ESelectNamesModel *model, gpointer closure)
|
||||
{
|
||||
static GtkType manager_type = 0;
|
||||
ESelectNamesManagerSection *section = closure;
|
||||
gtk_signal_emit (GTK_OBJECT (section->manager),
|
||||
e_select_names_manager_signals[CHANGED],
|
||||
section->id,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
static ESelectNamesManagerSection *
|
||||
e_select_names_manager_section_new (ESelectNamesManager *manager,
|
||||
const gchar *id,
|
||||
const gchar *title,
|
||||
ESelectNamesModel *model)
|
||||
{
|
||||
ESelectNamesManagerSection *section;
|
||||
|
||||
manager_type = gtk_type_unique (gtk_object_get_type (), &manager_info);
|
||||
g_return_val_if_fail (E_IS_SELECT_NAMES_MANAGER (manager), NULL);
|
||||
g_return_val_if_fail (E_IS_SELECT_NAMES_MODEL (model), NULL);
|
||||
|
||||
section = g_new0 (ESelectNamesManagerSection, 1);
|
||||
|
||||
section->id = g_strdup (id);
|
||||
section->title = g_strdup (title);
|
||||
|
||||
section->manager = manager;
|
||||
|
||||
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 section;
|
||||
}
|
||||
|
||||
static void
|
||||
e_select_names_manager_section_free (ESelectNamesManagerSection *section)
|
||||
{
|
||||
if (section == NULL)
|
||||
return;
|
||||
|
||||
g_free (section->id);
|
||||
g_free (section->title);
|
||||
|
||||
if (section->model) {
|
||||
gtk_signal_disconnect (GTK_OBJECT (section->model), section->changed_tag);
|
||||
gtk_object_unref (GTK_OBJECT (section->model));
|
||||
}
|
||||
|
||||
return manager_type;
|
||||
if (section->original_model) {
|
||||
gtk_object_unref (GTK_OBJECT (section->original_model));
|
||||
}
|
||||
|
||||
g_free (section);
|
||||
}
|
||||
|
||||
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
|
||||
|
||||
/* ESelectNamesManagerEntry routines */
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
static void
|
||||
popup_cb (EEntry *eentry, GdkEventButton *ev, gint pos, gpointer user_data)
|
||||
{
|
||||
ESelectNamesManagerEntry *entry = user_data;
|
||||
|
||||
e_select_names_popup (entry->model, ev, pos);
|
||||
}
|
||||
|
||||
static gint
|
||||
focus_in_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data)
|
||||
{
|
||||
ESelectNamesManagerEntry *entry = user_data;
|
||||
|
||||
e_select_names_model_cancel_cardify_all (entry->model);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
focus_out_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data)
|
||||
{
|
||||
ESelectNamesManagerEntry *entry = user_data;
|
||||
|
||||
e_select_names_model_clean (entry->model);
|
||||
|
||||
if (!e_entry_completion_popup_is_visible (entry->entry))
|
||||
e_select_names_model_cardify_all (entry->model, entry->manager->completion_book, 100);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
completion_popup_cb (EEntry *w, gint visible, gpointer user_data)
|
||||
{
|
||||
ESelectNamesManagerEntry *entry = user_data;
|
||||
|
||||
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
|
||||
completion_handler (EEntry *entry, ECompletionMatch *match)
|
||||
{
|
||||
ESelectNamesManagerEntry *mgr_entry;
|
||||
EDestination *dest;
|
||||
gint i, pos, start_pos, len;
|
||||
|
||||
if (match == NULL || match->user_data == NULL)
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static ESelectNamesManagerEntry *
|
||||
e_select_names_manager_entry_new (ESelectNamesManager *manager, ESelectNamesModel *model, const gchar *id)
|
||||
{
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (entry->entry),
|
||||
"completion_popup",
|
||||
GTK_SIGNAL_FUNC (completion_popup_cb),
|
||||
entry);
|
||||
|
||||
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);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void
|
||||
e_select_names_manager_entry_free (ESelectNamesManagerEntry *entry)
|
||||
{
|
||||
if (entry == NULL)
|
||||
return;
|
||||
|
||||
g_free (entry->id);
|
||||
gtk_object_unref (GTK_OBJECT (entry->model));
|
||||
gtk_object_unref (GTK_OBJECT (entry->entry));
|
||||
|
||||
g_free (entry);
|
||||
}
|
||||
|
||||
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
|
||||
|
||||
static void
|
||||
e_select_names_manager_save_models (ESelectNamesManager *manager)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
for (iter = manager->sections; iter != NULL; iter = g_list_next (iter)) {
|
||||
ESelectNamesManagerSection *section = iter->data;
|
||||
|
||||
if (section->original_model == NULL && section->model != NULL)
|
||||
section->original_model = e_select_names_model_duplicate (section->model);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
e_select_names_manager_revert_to_saved_models (ESelectNamesManager *manager)
|
||||
{
|
||||
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
|
||||
e_select_names_manager_discard_saved_models (ESelectNamesManager *manager)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
|
||||
|
||||
|
||||
static void
|
||||
open_book_cb (EBook *book, EBookStatus status, ESelectNamesManager *manager)
|
||||
{
|
||||
@ -139,6 +370,178 @@ e_select_names_manager_new (void)
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ESelectNamesManager lifecycle management and vcard loading/saving.
|
||||
*/
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
e_select_names_manager_add_section_with_limit (ESelectNamesManager *manager,
|
||||
const char *id,
|
||||
const char *title,
|
||||
gint limit)
|
||||
{
|
||||
ESelectNamesManagerSection *section;
|
||||
ESelectNamesModel *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);
|
||||
|
||||
manager->sections = g_list_append (manager->sections, section);
|
||||
|
||||
gtk_object_unref (GTK_OBJECT (model));
|
||||
}
|
||||
|
||||
ESelectNamesModel *
|
||||
e_select_names_manager_get_source (ESelectNamesManager *manager,
|
||||
const char *id)
|
||||
{
|
||||
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))
|
||||
return section->model;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
e_select_names_manager_create_entry (ESelectNamesManager *manager, const char *id)
|
||||
{
|
||||
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;
|
||||
|
||||
entry = e_select_names_manager_entry_new (manager, section->model, section->id);
|
||||
manager->entries = g_list_append (manager->entries, entry);
|
||||
|
||||
return GTK_WIDGET(entry->entry);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
e_select_names_clicked(ESelectNames *dialog, gint button, ESelectNamesManager *manager)
|
||||
{
|
||||
gnome_dialog_close(GNOME_DIALOG(dialog));
|
||||
|
||||
switch(button) {
|
||||
case 0:
|
||||
e_select_names_manager_discard_saved_models (manager);
|
||||
gtk_signal_emit (GTK_OBJECT (manager), e_select_names_manager_signals[OK]);
|
||||
break;
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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 ());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -146,12 +549,7 @@ e_select_names_manager_class_init (ESelectNamesManagerClass *klass)
|
||||
|
||||
object_class = GTK_OBJECT_CLASS(klass);
|
||||
|
||||
gtk_object_add_arg_type ("ESelectNamesManager::card",
|
||||
GTK_TYPE_OBJECT, GTK_ARG_READWRITE, ARG_CARD);
|
||||
|
||||
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;
|
||||
|
||||
e_select_names_manager_signals[CHANGED] =
|
||||
gtk_signal_new ("changed",
|
||||
@ -171,428 +569,48 @@ e_select_names_manager_class_init (ESelectNamesManagerClass *klass)
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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));
|
||||
|
||||
if (manager->names) {
|
||||
gtk_widget_destroy (GTK_WIDGET (manager->names));
|
||||
manager->names = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set_arg handler for the manager */
|
||||
static void
|
||||
e_select_names_manager_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
|
||||
{
|
||||
ESelectNamesManager *manager;
|
||||
|
||||
manager = E_SELECT_NAMES_MANAGER (object);
|
||||
|
||||
switch (arg_id) {
|
||||
case ARG_CARD:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get_arg handler for the manager */
|
||||
static void
|
||||
e_select_names_manager_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
|
||||
{
|
||||
ESelectNamesManager *manager;
|
||||
|
||||
manager = E_SELECT_NAMES_MANAGER (object);
|
||||
|
||||
switch (arg_id) {
|
||||
case ARG_CARD:
|
||||
break;
|
||||
default:
|
||||
arg->type = GTK_TYPE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *
|
||||
section_copy(const void *sec, void *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;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
g_free(section);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
entry_free(void *ent, void *data)
|
||||
{
|
||||
ESelectNamesManagerEntry *entry = ent;
|
||||
g_free(entry->id);
|
||||
if (entry->entry)
|
||||
gtk_object_unref(GTK_OBJECT(entry->entry));
|
||||
g_free(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* e_select_names_manager_init:
|
||||
*/
|
||||
static void
|
||||
e_select_names_manager_init (ESelectNamesManager *manager)
|
||||
* 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)
|
||||
{
|
||||
manager->sections = e_list_new(section_copy, section_free, manager);
|
||||
manager->entries = e_list_new(entry_copy, entry_free, manager);
|
||||
}
|
||||
static GtkType manager_type = 0;
|
||||
|
||||
static void
|
||||
section_model_changed_cb (ESelectNamesModel *model, gpointer closure)
|
||||
{
|
||||
ESelectNamesManagerSection *section = closure;
|
||||
gtk_signal_emit (GTK_OBJECT (section->manager),
|
||||
e_select_names_manager_signals[CHANGED],
|
||||
section->id,
|
||||
FALSE);
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
e_select_names_manager_add_section_with_limit (ESelectNamesManager *manager,
|
||||
const char *id,
|
||||
const char *title,
|
||||
gint limit)
|
||||
{
|
||||
ESelectNamesManagerSection *section;
|
||||
|
||||
section = g_new(ESelectNamesManagerSection, 1);
|
||||
section->id = g_strdup(id);
|
||||
section->title = g_strdup(title);
|
||||
|
||||
section->model = e_select_names_model_new();
|
||||
e_select_names_model_set_limit (section->model, limit);
|
||||
|
||||
section->original_model = NULL;
|
||||
|
||||
section->manager = manager;
|
||||
|
||||
section->changed_handler = gtk_signal_connect (GTK_OBJECT (section->model),
|
||||
"changed",
|
||||
GTK_SIGNAL_FUNC (section_model_changed_cb),
|
||||
section);
|
||||
|
||||
e_list_append(manager->sections, section);
|
||||
section_free(section, manager);
|
||||
}
|
||||
|
||||
ESelectNamesModel *
|
||||
e_select_names_manager_get_source (ESelectNamesManager *manager, const char *id)
|
||||
{
|
||||
EIterator *iterator;
|
||||
|
||||
g_return_val_if_fail (manager && E_IS_SELECT_NAMES_MANAGER (manager), NULL);
|
||||
g_return_val_if_fail (id, NULL);
|
||||
|
||||
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;
|
||||
}
|
||||
manager_type = gtk_type_unique (gtk_object_get_type (), &manager_info);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return manager_type;
|
||||
}
|
||||
|
||||
static void
|
||||
entry_destroyed(EEntry *entry, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
completion_handler (EEntry *entry, ECompletionMatch *match)
|
||||
{
|
||||
ESelectNamesModel *snm;
|
||||
EDestination *dest;
|
||||
gint i, pos, start_pos, len;
|
||||
|
||||
if (match == NULL || match->user_data == NULL)
|
||||
return;
|
||||
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_cb (EEntry *entry, GdkEventButton *ev, gint pos, ESelectNamesModel *model)
|
||||
{
|
||||
e_select_names_popup (model, ev, pos);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
focus_out_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"));
|
||||
ESelectNamesManager *manager = E_SELECT_NAMES_MANAGER (gtk_object_get_data (GTK_OBJECT (entry), "select_names_manager"));
|
||||
|
||||
e_select_names_model_clean (model);
|
||||
|
||||
if (!e_entry_completion_popup_is_visible (entry))
|
||||
e_select_names_model_cardify_all (model, manager->completion_book, 100);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
completion_popup_cb (EEntry *entry, gint visible, gpointer 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"));
|
||||
|
||||
if (!visible && !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry->canvas)))
|
||||
e_select_names_model_cardify_all (model, manager->completion_book, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
e_select_names_clicked(ESelectNames *dialog, gint button, ESelectNamesManager *manager)
|
||||
{
|
||||
gnome_dialog_close(GNOME_DIALOG(dialog));
|
||||
|
||||
switch(button) {
|
||||
case 0:
|
||||
/* We don't need to do much if they click on OK */
|
||||
|
||||
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));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
e_select_names_manager_activate_dialog (ESelectNamesManager *manager,
|
||||
const char *id)
|
||||
{
|
||||
EIterator *iterator;
|
||||
|
||||
if (manager->names) {
|
||||
g_assert (GTK_WIDGET_REALIZED (GTK_WIDGET (manager->names)));
|
||||
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 {
|
||||
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);
|
||||
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",
|
||||
GTK_SIGNAL_FUNC(gtk_widget_destroyed),
|
||||
&manager->names);
|
||||
gtk_widget_show(GTK_WIDGET(manager->names));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user