diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2011-08-05 17:32:23 +0800 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2011-08-05 18:14:19 +0800 |
commit | 820b5479bd14c6b408a3818f9bc287ad0a3e2fb8 (patch) | |
tree | b18e151d2f473a31c340c596aff30d9f9b393a14 | |
parent | d337ef853cc47ff78fbfa0ac54cf3d795832a2b7 (diff) | |
download | gsoc2013-empathy-820b5479bd14c6b408a3818f9bc287ad0a3e2fb8.tar gsoc2013-empathy-820b5479bd14c6b408a3818f9bc287ad0a3e2fb8.tar.gz gsoc2013-empathy-820b5479bd14c6b408a3818f9bc287ad0a3e2fb8.tar.bz2 gsoc2013-empathy-820b5479bd14c6b408a3818f9bc287ad0a3e2fb8.tar.lz gsoc2013-empathy-820b5479bd14c6b408a3818f9bc287ad0a3e2fb8.tar.xz gsoc2013-empathy-820b5479bd14c6b408a3818f9bc287ad0a3e2fb8.tar.zst gsoc2013-empathy-820b5479bd14c6b408a3818f9bc287ad0a3e2fb8.zip |
Add EmpathyContactChooser
This is a pure code refactoring from EmpathyInviteParticipantDialog, this
widget is not generic yet.
https://bugzilla.gnome.org/show_bug.cgi?id=656020
-rw-r--r-- | libempathy-gtk/Makefile.am | 2 | ||||
-rw-r--r-- | libempathy-gtk/empathy-contact-chooser.c | 493 | ||||
-rw-r--r-- | libempathy-gtk/empathy-contact-chooser.h | 55 | ||||
-rw-r--r-- | src/empathy-invite-participant-dialog.c | 410 |
4 files changed, 594 insertions, 366 deletions
diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index 7023ecfe5..2920a2a42 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -45,6 +45,7 @@ libempathy_gtk_handwritten_source = \ empathy-chat.c \ empathy-contact-blocking-dialog.c \ empathy-contact-dialogs.c \ + empathy-contact-chooser.c \ empathy-contact-list-store.c \ empathy-contact-list-view.c \ empathy-contact-menu.c \ @@ -106,6 +107,7 @@ libempathy_gtk_headers = \ empathy-chat.h \ empathy-contact-blocking-dialog.h \ empathy-contact-dialogs.h \ + empathy-contact-chooser.h \ empathy-contact-list-store.h \ empathy-contact-list-view.h \ empathy-contact-menu.h \ diff --git a/libempathy-gtk/empathy-contact-chooser.c b/libempathy-gtk/empathy-contact-chooser.c new file mode 100644 index 000000000..38956bac1 --- /dev/null +++ b/libempathy-gtk/empathy-contact-chooser.c @@ -0,0 +1,493 @@ +/* + * empathy-contact-chooser.c + * + * EmpathyContactChooser + * + * (c) 2009, Collabora Ltd. + * + * Authors: + * Danielle Madeley <danielle.madeley@collabora.co.uk> + */ + +#include <glib/gi18n.h> +#include <folks/folks-telepathy.h> + +#include "empathy-contact-chooser.h" + +#include <libempathy-gtk/empathy-individual-view.h> +#include <libempathy-gtk/empathy-ui-utils.h> + +G_DEFINE_TYPE (EmpathyContactChooser, + empathy_contact_chooser, GTK_TYPE_BOX); + +enum +{ + PROP_TP_CHAT = 1 +}; + +enum { + SIG_SELECTION_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +typedef struct _AddTemporaryIndividualCtx AddTemporaryIndividualCtx; + +struct _EmpathyContactChooserPrivate +{ + EmpathyTpChat *tp_chat; + TpAccountManager *account_mgr; + + EmpathyIndividualStore *store; + EmpathyIndividualView *view; + + GPtrArray *search_words; + gchar *search_str; + + /* Context representing the FolksIndividual which are added because of the + * current search from the user. */ + AddTemporaryIndividualCtx *add_temp_ctx; +}; + +static void +contact_chooser_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyContactChooser *self = (EmpathyContactChooser *) + object; + + switch (param_id) + { + case PROP_TP_CHAT: + g_value_set_object (value, self->priv->tp_chat); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +static void +contact_chooser_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyContactChooser *self = (EmpathyContactChooser *) + object; + + switch (param_id) + { + case PROP_TP_CHAT: + g_assert (self->priv->tp_chat == NULL); /* construct-only */ + self->priv->tp_chat = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + +struct _AddTemporaryIndividualCtx +{ + EmpathyContactChooser *self; + /* List of owned FolksIndividual */ + GList *individuals; +}; + +static AddTemporaryIndividualCtx * +add_temporary_individual_ctx_new (EmpathyContactChooser *self) +{ + AddTemporaryIndividualCtx *ctx = g_slice_new0 (AddTemporaryIndividualCtx); + + ctx->self = self; + return ctx; +} + +static void +add_temporary_individual_ctx_free (AddTemporaryIndividualCtx *ctx) +{ + GList *l; + + /* Remove all the individuals from the model */ + for (l = ctx->individuals; l != NULL; l = g_list_next (l)) + { + FolksIndividual *individual = l->data; + + individual_store_remove_individual_and_disconnect (ctx->self->priv->store, + individual); + + g_object_unref (individual); + } + + g_list_free (ctx->individuals); + g_slice_free (AddTemporaryIndividualCtx, ctx); +} + +static void +contact_chooser_dispose (GObject *object) +{ + EmpathyContactChooser *self = (EmpathyContactChooser *) + object; + + tp_clear_pointer (&self->priv->add_temp_ctx, + add_temporary_individual_ctx_free); + + tp_clear_object (&self->priv->tp_chat); + tp_clear_object (&self->priv->store); + tp_clear_pointer (&self->priv->search_words, g_ptr_array_unref); + tp_clear_pointer (&self->priv->search_str, g_free); + + tp_clear_object (&self->priv->account_mgr); + + G_OBJECT_CLASS (empathy_contact_chooser_parent_class)->dispose ( + object); +} + +static void +empathy_contact_chooser_class_init ( + EmpathyContactChooserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = contact_chooser_get_property; + object_class->set_property = contact_chooser_set_property; + object_class->dispose = contact_chooser_dispose; + + g_type_class_add_private (object_class, + sizeof (EmpathyContactChooserPrivate)); + + g_object_class_install_property (object_class, + PROP_TP_CHAT, + g_param_spec_object ("tp-chat", "EmpathyTpChat", "EmpathyTpChat", + EMPATHY_TYPE_TP_CHAT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + signals[SIG_SELECTION_CHANGED] = g_signal_new ("selection-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, FOLKS_TYPE_INDIVIDUAL); +} + +static void +view_selection_changed_cb (GtkWidget *treeview, + EmpathyContactChooser *self) +{ + FolksIndividual *individual; + + individual = empathy_individual_view_dup_selected (self->priv->view); + + g_signal_emit (self, signals[SIG_SELECTION_CHANGED], 0, individual); + + tp_clear_object (&individual); +} + +/* Return the TpContact of @individual which is on the same connection as the + * EmpathyTpChat */ +static TpContact * +get_tp_contact_for_chat (EmpathyContactChooser *self, + FolksIndividual *individual) +{ + TpContact *contact = NULL; + TpConnection *chat_conn; + GeeSet *personas; + GeeIterator *iter; + + chat_conn = tp_channel_borrow_connection (TP_CHANNEL (self->priv->tp_chat)); + + personas = folks_individual_get_personas (individual); + iter = gee_iterable_iterator (GEE_ITERABLE (personas)); + while (contact == FALSE && gee_iterator_next (iter)) + { + TpfPersona *persona = gee_iterator_get (iter); + TpConnection *contact_conn; + TpContact *contact_cur = NULL; + + if (TPF_IS_PERSONA (persona)) + { + contact_cur = tpf_persona_get_contact (persona); + if (contact_cur != NULL) + { + contact_conn = tp_contact_get_connection (contact_cur); + + if (!tp_strdiff (tp_proxy_get_object_path (contact_conn), + tp_proxy_get_object_path (chat_conn))) + contact = contact_cur; + } + } + + g_clear_object (&persona); + } + g_clear_object (&iter); + + return contact; +} + +static gboolean +filter_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + EmpathyContactChooser *self = user_data; + FolksIndividual *individual; + TpContact *contact; + gboolean is_online; + GList *members, *l; + gboolean display = FALSE; + + gtk_tree_model_get (model, iter, + EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, + EMPATHY_INDIVIDUAL_STORE_COL_IS_ONLINE, &is_online, + -1); + + if (individual == NULL) + goto out; + + if (self->priv->search_words == NULL) + { + /* Not searching, display online contacts */ + if (!is_online) + goto out; + } + else + { + if (!empathy_individual_match_string (individual, + self->priv->search_str, self->priv->search_words)) + goto out; + } + + /* Filter out individuals not having a persona on the same connection as the + * EmpathyTpChat. */ + contact = get_tp_contact_for_chat (self, individual); + + if (contact == NULL) + goto out; + + /* Filter out contacts which are already in the chat */ + members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST ( + self->priv->tp_chat)); + + display = TRUE; + + for (l = members; l != NULL; l = g_list_next (l)) + { + EmpathyContact *member = l->data; + TpHandle handle; + + /* Try to get the non-channel specific handle. */ + handle = tp_channel_group_get_handle_owner ( + TP_CHANNEL (self->priv->tp_chat), + empathy_contact_get_handle (member)); + if (handle == 0) + handle = empathy_contact_get_handle (member); + + if (handle == tp_contact_get_handle (contact)) + { + display = FALSE; + break; + } + } + + g_list_free_full (members, g_object_unref); + +out: + tp_clear_object (&individual); + return display; +} + +static void +get_contacts_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyContactChooser *self = + (EmpathyContactChooser *) weak_object; + AddTemporaryIndividualCtx *ctx = user_data; + TpAccount *account; + TpfPersonaStore *store; + FolksIndividual *individual; + TpfPersona *persona_new; + GeeSet *personas; + + if (self->priv->add_temp_ctx != ctx) + /* another request has been started */ + return; + + if (n_contacts != 1) + return; + + account = g_object_get_data (G_OBJECT (connection), "account"); + + store = tpf_persona_store_new (account); + personas = GEE_SET ( + gee_hash_set_new (FOLKS_TYPE_PERSONA, g_object_ref, g_object_unref, + g_direct_hash, g_direct_equal)); + persona_new = tpf_persona_new (contacts[0], store); + gee_collection_add (GEE_COLLECTION (personas), + tpf_persona_new (contacts[0], store)); + + individual = folks_individual_new (personas); + + /* Pass ownership to the list */ + ctx->individuals = g_list_prepend (ctx->individuals, individual); + + individual_store_add_individual_and_connect (self->priv->store, individual); + + g_clear_object (&persona_new); + g_clear_object (&personas); + g_object_unref (store); +} + +static void +add_temporary_individuals (EmpathyContactChooser *self, + const gchar *id) +{ + GList *accounts, *l; + + tp_clear_pointer (&self->priv->add_temp_ctx, + add_temporary_individual_ctx_free); + + if (tp_str_empty (id)) + return; + + self->priv->add_temp_ctx = add_temporary_individual_ctx_new (self); + + /* Try to add an individual for each connected account */ + accounts = tp_account_manager_get_valid_accounts (self->priv->account_mgr); + for (l = accounts; l != NULL; l = g_list_next (l)) + { + TpAccount *account = l->data; + TpConnection *conn; + TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS, + TP_CONTACT_FEATURE_AVATAR_DATA, + TP_CONTACT_FEATURE_PRESENCE, + TP_CONTACT_FEATURE_CAPABILITIES }; + + conn = tp_account_get_connection (account); + if (conn == NULL) + continue; + + /* One day we'll have tp_connection_get_account()... */ + g_object_set_data_full (G_OBJECT (conn), "account", + g_object_ref (account), g_object_unref); + + tp_connection_get_contacts_by_id (conn, 1, &id, G_N_ELEMENTS (features), + features, get_contacts_cb, self->priv->add_temp_ctx, NULL, + G_OBJECT (self)); + } + + g_list_free (accounts); +} + +static void +search_text_changed (GtkEntry *entry, + EmpathyContactChooser *self) +{ + const gchar *id; + + tp_clear_pointer (&self->priv->search_words, g_ptr_array_unref); + tp_clear_pointer (&self->priv->search_str, g_free); + + id = gtk_entry_get_text (entry); + + self->priv->search_words = empathy_live_search_strip_utf8_string (id); + self->priv->search_str = g_strdup (id); + + add_temporary_individuals (self, id); + + empathy_individual_view_refilter (self->priv->view); +} + +static void +empathy_contact_chooser_init (EmpathyContactChooser *self) +{ + EmpathyIndividualManager *mgr; + GtkTreeSelection *selection; + GtkWidget *scroll; + GtkWidget *search_entry; + GQuark features[] = { TP_ACCOUNT_MANAGER_FEATURE_CORE, 0 }; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, EMPATHY_TYPE_CONTACT_CHOOSER, + EmpathyContactChooserPrivate); + + self->priv->account_mgr = tp_account_manager_dup (); + + /* We don't wait for the CORE feature to be prepared, which is fine as we + * won't use the account manager until user starts searching. Furthermore, + * the AM has probably already been prepared by another Empathy + * component. */ + tp_proxy_prepare_async (self->priv->account_mgr, features, NULL, NULL); + + /* Search entry */ + search_entry = gtk_entry_new (); + gtk_box_pack_start (GTK_BOX (self), search_entry, FALSE, TRUE, 6); + gtk_widget_show (search_entry); + + g_signal_connect (search_entry, "changed", + G_CALLBACK (search_text_changed), self); + + /* Add the treeview */ + mgr = empathy_individual_manager_dup_singleton (); + self->priv->store = empathy_individual_store_new (mgr); + g_object_unref (mgr); + + empathy_individual_store_set_show_groups (self->priv->store, FALSE); + + self->priv->view = empathy_individual_view_new (self->priv->store, + EMPATHY_INDIVIDUAL_VIEW_FEATURE_NONE, EMPATHY_INDIVIDUAL_FEATURE_NONE); + + empathy_individual_view_set_custom_filter (self->priv->view, + filter_func, self); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->view)); + + g_signal_connect (selection, "changed", + G_CALLBACK (view_selection_changed_cb), self); + + scroll = gtk_scrolled_window_new (NULL, NULL); + + gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->priv->view)); + + gtk_box_pack_start (GTK_BOX (self), scroll, TRUE, TRUE, 6); + gtk_widget_show (GTK_WIDGET (self->priv->view)); + gtk_widget_show (scroll); +} + +GtkWidget * +empathy_contact_chooser_new (EmpathyTpChat *tp_chat) +{ + g_return_val_if_fail (EMPATHY_IS_TP_CHAT (tp_chat), NULL); + + return g_object_new (EMPATHY_TYPE_CONTACT_CHOOSER, + "orientation", GTK_ORIENTATION_VERTICAL, + "tp-chat", tp_chat, + NULL); +} + +TpContact * +empathy_contact_chooser_get_selected (EmpathyContactChooser *self) +{ + FolksIndividual *individual; + TpContact *contact; + + individual = empathy_individual_view_dup_selected (self->priv->view); + if (individual == NULL) + return NULL; + + contact = get_tp_contact_for_chat (self, individual); + + g_object_unref (individual); + return contact; +} diff --git a/libempathy-gtk/empathy-contact-chooser.h b/libempathy-gtk/empathy-contact-chooser.h new file mode 100644 index 000000000..5af938d5d --- /dev/null +++ b/libempathy-gtk/empathy-contact-chooser.h @@ -0,0 +1,55 @@ +/* + * empathy-contact-chooser.h + * + * EmpathyContactChooser + * + * (c) 2010, Collabora Ltd. + * + * Authors: + * Guillaume Desmottes <guillaume.desmottes@collabora.com> + */ + +#ifndef __EMPATHY_CONTACT_CHOOSER_H__ +#define __EMPATHY_CONTACT_CHOOSER_H__ + +#include <gtk/gtk.h> + +#include <telepathy-glib/account.h> + +#include "libempathy/empathy-tp-chat.h" + +G_BEGIN_DECLS + +#define EMPATHY_TYPE_CONTACT_CHOOSER (empathy_contact_chooser_get_type ()) +#define EMPATHY_CONTACT_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_CONTACT_CHOOSER, EmpathyContactChooser)) +#define EMPATHY_CONTACT_CHOOSER_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), EMPATHY_TYPE_CONTACT_CHOOSER, EmpathyContactChooserClass)) +#define EMPATHY_IS_CONTACT_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_CONTACT_CHOOSER)) +#define EMPATHY_IS_CONTACT_CHOOSER_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), EMPATHY_TYPE_CONTACT_CHOOSER)) +#define EMPATHY_CONTACT_CHOOSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_CONTACT_CHOOSER, EmpathyContactChooserClass)) + +typedef struct _EmpathyContactChooser EmpathyContactChooser; +typedef struct _EmpathyContactChooserClass EmpathyContactChooserClass; +typedef struct _EmpathyContactChooserPrivate EmpathyContactChooserPrivate; + +struct _EmpathyContactChooser +{ + GtkBox parent; + + EmpathyContactChooserPrivate *priv; +}; + +struct _EmpathyContactChooserClass +{ + GtkBoxClass parent_class; +}; + +GType empathy_contact_chooser_get_type (void); + +GtkWidget * empathy_contact_chooser_new (EmpathyTpChat *tp_chat); + +TpContact * empathy_contact_chooser_get_selected ( + EmpathyContactChooser *self); + +G_END_DECLS + +#endif diff --git a/src/empathy-invite-participant-dialog.c b/src/empathy-invite-participant-dialog.c index 1551b475d..f6471fbc7 100644 --- a/src/empathy-invite-participant-dialog.c +++ b/src/empathy-invite-participant-dialog.c @@ -14,6 +14,7 @@ #include "empathy-invite-participant-dialog.h" +#include <libempathy-gtk/empathy-contact-chooser.h> #include <libempathy-gtk/empathy-individual-view.h> #include <libempathy-gtk/empathy-ui-utils.h> @@ -25,24 +26,12 @@ enum PROP_TP_CHAT = 1 }; -typedef struct _AddTemporaryIndividualCtx AddTemporaryIndividualCtx; - struct _EmpathyInviteParticipantDialogPrivate { EmpathyTpChat *tp_chat; - TpAccountManager *account_mgr; - - EmpathyIndividualStore *store; - EmpathyIndividualView *view; + GtkWidget *chooser; GtkWidget *invite_button; - - GPtrArray *search_words; - gchar *search_str; - - /* Context representing the FolksIndividual which are added because of the - * current search from the user. */ - AddTemporaryIndividualCtx *add_temp_ctx; }; static void @@ -86,340 +75,35 @@ invite_participant_dialog_set_property (GObject *object, }; } -struct _AddTemporaryIndividualCtx -{ - EmpathyInviteParticipantDialog *self; - /* List of owned FolksIndividual */ - GList *individuals; -}; - -static AddTemporaryIndividualCtx * -add_temporary_individual_ctx_new (EmpathyInviteParticipantDialog *self) -{ - AddTemporaryIndividualCtx *ctx = g_slice_new0 (AddTemporaryIndividualCtx); - - ctx->self = self; - return ctx; -} - -static void -add_temporary_individual_ctx_free (AddTemporaryIndividualCtx *ctx) -{ - GList *l; - - /* Remove all the individuals from the model */ - for (l = ctx->individuals; l != NULL; l = g_list_next (l)) - { - FolksIndividual *individual = l->data; - - individual_store_remove_individual_and_disconnect (ctx->self->priv->store, - individual); - - g_object_unref (individual); - } - - g_list_free (ctx->individuals); - g_slice_free (AddTemporaryIndividualCtx, ctx); -} - static void invite_participant_dialog_dispose (GObject *object) { EmpathyInviteParticipantDialog *self = (EmpathyInviteParticipantDialog *) object; - tp_clear_pointer (&self->priv->add_temp_ctx, - add_temporary_individual_ctx_free); - tp_clear_object (&self->priv->tp_chat); - tp_clear_object (&self->priv->store); - tp_clear_pointer (&self->priv->search_words, g_ptr_array_unref); - tp_clear_pointer (&self->priv->search_str, g_free); - - tp_clear_object (&self->priv->account_mgr); G_OBJECT_CLASS (empathy_invite_participant_dialog_parent_class)->dispose ( object); } static void -empathy_invite_participant_dialog_class_init ( - EmpathyInviteParticipantDialogClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->get_property = invite_participant_dialog_get_property; - object_class->set_property = invite_participant_dialog_set_property; - object_class->dispose = invite_participant_dialog_dispose; - - g_type_class_add_private (object_class, - sizeof (EmpathyInviteParticipantDialogPrivate)); - - g_object_class_install_property (object_class, - PROP_TP_CHAT, - g_param_spec_object ("tp-chat", "EmpathyTpChat", "EmpathyTpChat", - EMPATHY_TYPE_TP_CHAT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); -} - -static void -view_selection_changed_cb (GtkWidget *treeview, +selection_changed_cb (GtkWidget *treeview, + FolksIndividual *selected, EmpathyInviteParticipantDialog *self) { - FolksIndividual *individual; - - individual = empathy_individual_view_dup_selected (self->priv->view); - - gtk_widget_set_sensitive (self->priv->invite_button, individual != NULL); - - tp_clear_object (&individual); -} - -/* Return the TpContact of @individual which is on the same connection as the - * EmpathyTpChat */ -static TpContact * -get_tp_contact_for_chat (EmpathyInviteParticipantDialog *self, - FolksIndividual *individual) -{ - TpContact *contact = NULL; - TpConnection *chat_conn; - GeeSet *personas; - GeeIterator *iter; - - chat_conn = tp_channel_borrow_connection ((TpChannel *) self->priv->tp_chat); - - personas = folks_individual_get_personas (individual); - iter = gee_iterable_iterator (GEE_ITERABLE (personas)); - while (contact == FALSE && gee_iterator_next (iter)) - { - TpfPersona *persona = gee_iterator_get (iter); - TpConnection *contact_conn; - TpContact *contact_cur = NULL; - - if (TPF_IS_PERSONA (persona)) - { - contact_cur = tpf_persona_get_contact (persona); - if (contact_cur != NULL) - { - contact_conn = tp_contact_get_connection (contact_cur); - - if (!tp_strdiff (tp_proxy_get_object_path (contact_conn), - tp_proxy_get_object_path (chat_conn))) - contact = contact_cur; - } - } - - g_clear_object (&persona); - } - g_clear_object (&iter); - - return contact; -} - -static gboolean -filter_func (GtkTreeModel *model, - GtkTreeIter *iter, - gpointer user_data) -{ - EmpathyInviteParticipantDialog *self = user_data; - FolksIndividual *individual; - TpContact *contact; - gboolean is_online; - GList *members, *l; - gboolean display = FALSE; - - gtk_tree_model_get (model, iter, - EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, - EMPATHY_INDIVIDUAL_STORE_COL_IS_ONLINE, &is_online, - -1); - - if (individual == NULL) - goto out; - - if (self->priv->search_words == NULL) - { - /* Not searching, display online contacts */ - if (!is_online) - goto out; - } - else - { - if (!empathy_individual_match_string (individual, - self->priv->search_str, self->priv->search_words)) - goto out; - } - - /* Filter out individuals not having a persona on the same connection as the - * EmpathyTpChat. */ - contact = get_tp_contact_for_chat (self, individual); - - if (contact == NULL) - goto out; - - /* Filter out contacts which are already in the chat */ - members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST ( - self->priv->tp_chat)); - - display = TRUE; - - for (l = members; l != NULL; l = g_list_next (l)) - { - EmpathyContact *member = l->data; - TpHandle handle; - - /* Try to get the non-channel specific handle. */ - handle = tp_channel_group_get_handle_owner ( - TP_CHANNEL (self->priv->tp_chat), - empathy_contact_get_handle (member)); - if (handle == 0) - handle = empathy_contact_get_handle (member); - - if (handle == tp_contact_get_handle (contact)) - { - display = FALSE; - break; - } - } - - g_list_free_full (members, g_object_unref); - -out: - tp_clear_object (&individual); - return display; + gtk_widget_set_sensitive (self->priv->invite_button, selected != NULL); } static void -get_contacts_cb (TpConnection *connection, - guint n_contacts, - TpContact * const *contacts, - const gchar * const *requested_ids, - GHashTable *failed_id_errors, - const GError *error, - gpointer user_data, - GObject *weak_object) +invite_participant_dialog_constructed (GObject *object) { EmpathyInviteParticipantDialog *self = - (EmpathyInviteParticipantDialog *) weak_object; - AddTemporaryIndividualCtx *ctx = user_data; - TpAccount *account; - TpfPersonaStore *store; - FolksIndividual *individual; - TpfPersona *persona_new; - GeeSet *personas; - - if (self->priv->add_temp_ctx != ctx) - /* another request has been started */ - return; - - if (n_contacts != 1) - return; - - account = g_object_get_data (G_OBJECT (connection), "account"); - - store = tpf_persona_store_new (account); - personas = GEE_SET ( - gee_hash_set_new (FOLKS_TYPE_PERSONA, g_object_ref, g_object_unref, - g_direct_hash, g_direct_equal)); - persona_new = tpf_persona_new (contacts[0], store); - gee_collection_add (GEE_COLLECTION (personas), - tpf_persona_new (contacts[0], store)); - - individual = folks_individual_new (personas); - - /* Pass ownership to the list */ - ctx->individuals = g_list_prepend (ctx->individuals, individual); - - individual_store_add_individual_and_connect (self->priv->store, individual); - - g_clear_object (&persona_new); - g_clear_object (&personas); - g_object_unref (store); -} - -static void -add_temporary_individuals (EmpathyInviteParticipantDialog *self, - const gchar *id) -{ - GList *accounts, *l; - - tp_clear_pointer (&self->priv->add_temp_ctx, - add_temporary_individual_ctx_free); - - if (tp_str_empty (id)) - return; - - self->priv->add_temp_ctx = add_temporary_individual_ctx_new (self); - - /* Try to add an individual for each connected account */ - accounts = tp_account_manager_get_valid_accounts (self->priv->account_mgr); - for (l = accounts; l != NULL; l = g_list_next (l)) - { - TpAccount *account = l->data; - TpConnection *conn; - TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS, - TP_CONTACT_FEATURE_AVATAR_DATA, - TP_CONTACT_FEATURE_PRESENCE, - TP_CONTACT_FEATURE_CAPABILITIES }; - - conn = tp_account_get_connection (account); - if (conn == NULL) - continue; - - /* One day we'll have tp_connection_get_account()... */ - g_object_set_data_full (G_OBJECT (conn), "account", - g_object_ref (account), g_object_unref); - - tp_connection_get_contacts_by_id (conn, 1, &id, G_N_ELEMENTS (features), - features, get_contacts_cb, self->priv->add_temp_ctx, NULL, - G_OBJECT (self)); - } - - g_list_free (accounts); -} - -static void -search_text_changed (GtkEntry *entry, - EmpathyInviteParticipantDialog *self) -{ - const gchar *id; - - tp_clear_pointer (&self->priv->search_words, g_ptr_array_unref); - tp_clear_pointer (&self->priv->search_str, g_free); - - id = gtk_entry_get_text (entry); - - self->priv->search_words = empathy_live_search_strip_utf8_string (id); - self->priv->search_str = g_strdup (id); - - add_temporary_individuals (self, id); - - empathy_individual_view_refilter (self->priv->view); -} - -static void -empathy_invite_participant_dialog_init (EmpathyInviteParticipantDialog *self) -{ + (EmpathyInviteParticipantDialog *) object; GtkDialog *dialog = GTK_DIALOG (self); GtkWidget *label; char *str; GtkWidget *content; - EmpathyIndividualManager *mgr; - GtkTreeSelection *selection; - GtkWidget *scroll; - GtkWidget *search_entry; - GQuark features[] = { TP_ACCOUNT_MANAGER_FEATURE_CORE, 0 }; - - self->priv = G_TYPE_INSTANCE_GET_PRIVATE ( - self, EMPATHY_TYPE_INVITE_PARTICIPANT_DIALOG, - EmpathyInviteParticipantDialogPrivate); - - self->priv->account_mgr = tp_account_manager_dup (); - - /* We don't wait for the CORE feature to be prepared, which is fine as we - * won't use the account manager until user starts searching. Furthermore, - * the AM has probably already been prepared by another Empathy - * component. */ - tp_proxy_prepare_async (self->priv->account_mgr, features, NULL, NULL); content = gtk_dialog_get_content_area (dialog); @@ -436,39 +120,13 @@ empathy_invite_participant_dialog_init (EmpathyInviteParticipantDialog *self) gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); - /* Search entry */ - search_entry = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (content), search_entry, FALSE, TRUE, 6); - gtk_widget_show (search_entry); - - g_signal_connect (search_entry, "changed", - G_CALLBACK (search_text_changed), self); - - /* Add the treeview */ - mgr = empathy_individual_manager_dup_singleton (); - self->priv->store = empathy_individual_store_new (mgr); - g_object_unref (mgr); - - empathy_individual_store_set_show_groups (self->priv->store, FALSE); + /* contact chooser */ + self->priv->chooser = empathy_contact_chooser_new (self->priv->tp_chat); + gtk_box_pack_start (GTK_BOX (content), self->priv->chooser, TRUE, TRUE, 6); + gtk_widget_show (self->priv->chooser); - self->priv->view = empathy_individual_view_new (self->priv->store, - EMPATHY_INDIVIDUAL_VIEW_FEATURE_NONE, EMPATHY_INDIVIDUAL_FEATURE_NONE); - - empathy_individual_view_set_custom_filter (self->priv->view, - filter_func, self); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->view)); - - g_signal_connect (selection, "changed", - G_CALLBACK (view_selection_changed_cb), self); - - scroll = gtk_scrolled_window_new (NULL, NULL); - - gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->priv->view)); - - gtk_box_pack_start (GTK_BOX (content), scroll, TRUE, TRUE, 6); - gtk_widget_show (GTK_WIDGET (self->priv->view)); - gtk_widget_show (scroll); + g_signal_connect (self->priv->chooser, "selection-changed", + G_CALLBACK (selection_changed_cb), self); self->priv->invite_button = gtk_dialog_add_button (dialog, _("Invite"), GTK_RESPONSE_ACCEPT); @@ -481,6 +139,35 @@ empathy_invite_participant_dialog_init (EmpathyInviteParticipantDialog *self) gtk_window_set_default_size (GTK_WINDOW (self), -1, 400); } +static void +empathy_invite_participant_dialog_class_init ( + EmpathyInviteParticipantDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->get_property = invite_participant_dialog_get_property; + object_class->set_property = invite_participant_dialog_set_property; + object_class->constructed = invite_participant_dialog_constructed; + object_class->dispose = invite_participant_dialog_dispose; + + g_type_class_add_private (object_class, + sizeof (EmpathyInviteParticipantDialogPrivate)); + + g_object_class_install_property (object_class, + PROP_TP_CHAT, + g_param_spec_object ("tp-chat", "EmpathyTpChat", "EmpathyTpChat", + EMPATHY_TYPE_TP_CHAT, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); +} + +static void +empathy_invite_participant_dialog_init (EmpathyInviteParticipantDialog *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE ( + self, EMPATHY_TYPE_INVITE_PARTICIPANT_DIALOG, + EmpathyInviteParticipantDialogPrivate); +} + GtkWidget * empathy_invite_participant_dialog_new (GtkWindow *parent, EmpathyTpChat *tp_chat) @@ -501,15 +188,6 @@ TpContact * empathy_invite_participant_dialog_get_selected ( EmpathyInviteParticipantDialog *self) { - FolksIndividual *individual; - TpContact *contact; - - individual = empathy_individual_view_dup_selected (self->priv->view); - if (individual == NULL) - return NULL; - - contact = get_tp_contact_for_chat (self, individual); - - g_object_unref (individual); - return contact; + return empathy_contact_chooser_get_selected ( + EMPATHY_CONTACT_CHOOSER (self->priv->chooser)); } |