]> git.0d.be Git - empathy.git/blob - src/empathy-invite-participant-dialog.c
use g_list_free_full()
[empathy.git] / src / empathy-invite-participant-dialog.c
1 /*
2  * empathy-invite-participant-dialog.c
3  *
4  * EmpathyInviteParticipantDialog
5  *
6  * (c) 2009, Collabora Ltd.
7  *
8  * Authors:
9  *    Danielle Madeley <danielle.madeley@collabora.co.uk>
10  */
11
12 #include <glib/gi18n.h>
13 #include <folks/folks-telepathy.h>
14
15 #include "empathy-invite-participant-dialog.h"
16
17 #include <libempathy-gtk/empathy-individual-view.h>
18
19 G_DEFINE_TYPE (EmpathyInviteParticipantDialog,
20     empathy_invite_participant_dialog, GTK_TYPE_DIALOG);
21
22 enum
23 {
24   PROP_TP_CHAT = 1
25 };
26
27 struct _EmpathyInviteParticipantDialogPrivate
28 {
29   EmpathyTpChat *tp_chat;
30
31   EmpathyIndividualStore *store;
32   EmpathyIndividualView *view;
33
34   GtkWidget *invite_button;
35 };
36
37 static void
38 invite_participant_dialog_get_property (GObject *object,
39     guint param_id,
40     GValue *value,
41     GParamSpec *pspec)
42 {
43   EmpathyInviteParticipantDialog *self = (EmpathyInviteParticipantDialog *)
44     object;
45
46   switch (param_id)
47     {
48     case PROP_TP_CHAT:
49       g_value_set_object (value, self->priv->tp_chat);
50       break;
51     default:
52       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
53       break;
54     };
55 }
56
57 static void
58 invite_participant_dialog_set_property (GObject *object,
59     guint param_id,
60     const GValue *value,
61     GParamSpec *pspec)
62 {
63   EmpathyInviteParticipantDialog *self = (EmpathyInviteParticipantDialog *)
64     object;
65
66   switch (param_id)
67     {
68     case PROP_TP_CHAT:
69       g_assert (self->priv->tp_chat == NULL); /* construct-only */
70       self->priv->tp_chat = g_value_dup_object (value);
71       break;
72     default:
73       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
74       break;
75     };
76 }
77
78 static void
79 invite_participant_dialog_dispose (GObject *object)
80 {
81   EmpathyInviteParticipantDialog *self = (EmpathyInviteParticipantDialog *)
82     object;
83
84   tp_clear_object (&self->priv->tp_chat);
85   tp_clear_object (&self->priv->store);
86
87   G_OBJECT_CLASS (empathy_invite_participant_dialog_parent_class)->dispose (
88       object);
89 }
90
91 static void
92 empathy_invite_participant_dialog_class_init (
93     EmpathyInviteParticipantDialogClass *klass)
94 {
95   GObjectClass *object_class = G_OBJECT_CLASS (klass);
96
97   object_class->get_property = invite_participant_dialog_get_property;
98   object_class->set_property = invite_participant_dialog_set_property;
99   object_class->dispose = invite_participant_dialog_dispose;
100
101   g_type_class_add_private (object_class,
102       sizeof (EmpathyInviteParticipantDialogPrivate));
103
104   g_object_class_install_property (object_class,
105       PROP_TP_CHAT,
106       g_param_spec_object ("tp-chat", "EmpathyTpChat", "EmpathyTpChat",
107           EMPATHY_TYPE_TP_CHAT,
108           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
109 }
110
111 static void
112 view_selection_changed_cb (GtkWidget *treeview,
113     EmpathyInviteParticipantDialog *self)
114 {
115   FolksIndividual *individual;
116
117   individual = empathy_individual_view_dup_selected (self->priv->view);
118
119   gtk_widget_set_sensitive (self->priv->invite_button, individual != NULL);
120
121   g_object_unref (individual);
122 }
123
124 /* Return the TpContact of @individual which is on the same connection as the
125  * EmpathyTpChat */
126 static TpContact *
127 get_tp_contact_for_chat (EmpathyInviteParticipantDialog *self,
128     FolksIndividual *individual)
129 {
130   GList *personas, *l;
131   TpConnection *chat_conn;
132
133   chat_conn = empathy_tp_chat_get_connection (self->priv->tp_chat);
134
135   personas = folks_individual_get_personas (individual);
136
137   for (l = personas; l != NULL; l = g_list_next (l))
138     {
139       TpfPersona *persona = l->data;
140       TpContact *contact;
141       TpConnection *contact_conn;
142
143       if (!TPF_IS_PERSONA (persona))
144         continue;
145
146       contact = tpf_persona_get_contact (persona);
147       if (contact == NULL)
148         continue;
149
150       contact_conn = tp_contact_get_connection (contact);
151
152       if (!tp_strdiff (tp_proxy_get_object_path (contact_conn),
153             tp_proxy_get_object_path (chat_conn)))
154         return contact;
155     }
156
157   return NULL;
158 }
159
160 static gboolean
161 filter_func (GtkTreeModel *model,
162     GtkTreeIter *iter,
163     gpointer user_data)
164 {
165   EmpathyInviteParticipantDialog *self = user_data;
166   FolksIndividual *individual;
167   TpContact *contact;
168   gboolean is_online;
169   GList *members, *l;
170   gboolean display = FALSE;
171   TpChannel *channel;
172
173   gtk_tree_model_get (model, iter,
174       EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
175       EMPATHY_INDIVIDUAL_STORE_COL_IS_ONLINE, &is_online,
176       -1);
177
178   if (individual == NULL || !is_online)
179     goto out;
180
181   /* Filter out individuals not having a persona on the same connection as the
182    * EmpathyTpChat. */
183   contact = get_tp_contact_for_chat (self, individual);
184
185   if (contact == NULL)
186     goto out;
187
188   /* Filter out contacts which are already in the chat */
189   members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (
190         self->priv->tp_chat));
191
192   display = TRUE;
193   channel = empathy_tp_chat_get_channel (self->priv->tp_chat);
194
195   for (l = members; l != NULL; l = g_list_next (l))
196     {
197       EmpathyContact *member = l->data;
198       TpHandle handle;
199
200       /* Try to get the non-channel specific handle. */
201       handle = tp_channel_group_get_handle_owner (channel,
202           empathy_contact_get_handle (member));
203       if (handle == 0)
204         handle = empathy_contact_get_handle (member);
205
206       if (handle == tp_contact_get_handle (contact))
207         {
208           display = FALSE;
209           break;
210         }
211     }
212
213   g_list_free_full (members, g_object_unref);
214
215 out:
216   tp_clear_object (&individual);
217   return display;
218 }
219
220 static void
221 empathy_invite_participant_dialog_init (EmpathyInviteParticipantDialog *self)
222 {
223   GtkDialog *dialog = GTK_DIALOG (self);
224   GtkWidget *label;
225   char *str;
226   GtkWidget *content;
227   EmpathyIndividualManager *mgr;
228   GtkTreeSelection *selection;
229   GtkWidget *scroll;
230
231   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (
232       self, EMPATHY_TYPE_INVITE_PARTICIPANT_DIALOG,
233       EmpathyInviteParticipantDialogPrivate);
234
235   content = gtk_dialog_get_content_area (dialog);
236
237   label = gtk_label_new (NULL);
238   str = g_strdup_printf (
239       "<span size=\"x-large\" weight=\"bold\">%s</span>\n\n%s",
240       _("Invite Participant"),
241       _("Choose a contact to invite into the conversation:"));
242   gtk_label_set_markup (GTK_LABEL (label), str);
243   g_free (str);
244
245   gtk_box_pack_start (GTK_BOX (content), label, FALSE, TRUE, 6);
246   gtk_widget_show (label);
247
248   gtk_dialog_add_button (dialog, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
249
250   /* Add the treeview */
251   mgr = empathy_individual_manager_dup_singleton ();
252   self->priv->store = empathy_individual_store_new (mgr);
253   g_object_unref (mgr);
254
255   empathy_individual_store_set_show_groups (self->priv->store, FALSE);
256
257   self->priv->view = empathy_individual_view_new (self->priv->store,
258       EMPATHY_INDIVIDUAL_VIEW_FEATURE_NONE, EMPATHY_INDIVIDUAL_FEATURE_NONE);
259
260   empathy_individual_view_set_custom_filter (self->priv->view,
261       filter_func, self);
262
263   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->priv->view));
264
265   g_signal_connect (selection, "changed",
266       G_CALLBACK (view_selection_changed_cb), self);
267
268   scroll = gtk_scrolled_window_new (NULL, NULL);
269
270   gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (self->priv->view));
271
272   gtk_box_pack_start (GTK_BOX (content), scroll, TRUE, TRUE, 6);
273   gtk_widget_show (GTK_WIDGET (self->priv->view));
274   gtk_widget_show (scroll);
275
276   self->priv->invite_button = gtk_dialog_add_button (dialog, _("Invite"),
277       GTK_RESPONSE_ACCEPT);
278   gtk_widget_set_sensitive (self->priv->invite_button, FALSE);
279
280   gtk_window_set_title (GTK_WINDOW (self), _("Invite Participant"));
281   gtk_window_set_role (GTK_WINDOW (self), "invite_participant");
282
283   /* Set a default height so a few contacts are displayed */
284   gtk_window_set_default_size (GTK_WINDOW (self), -1, 400);
285 }
286
287 GtkWidget *
288 empathy_invite_participant_dialog_new (GtkWindow *parent,
289     EmpathyTpChat *tp_chat)
290 {
291   GtkWidget *self = g_object_new (EMPATHY_TYPE_INVITE_PARTICIPANT_DIALOG,
292       "tp-chat", tp_chat,
293       NULL);
294
295   if (parent != NULL)
296     {
297       gtk_window_set_transient_for (GTK_WINDOW (self), parent);
298     }
299
300   return self;
301 }
302
303 TpContact *
304 empathy_invite_participant_dialog_get_selected (
305     EmpathyInviteParticipantDialog *self)
306 {
307   FolksIndividual *individual;
308   TpContact *contact;
309
310   individual = empathy_individual_view_dup_selected (self->priv->view);
311   if (individual == NULL)
312     return NULL;
313
314   contact = get_tp_contact_for_chat (self, individual);
315
316   g_object_unref (individual);
317   return contact;
318 }