]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-blocking-dialog.c
Handle the case where there are no accounts with deny channels
[empathy.git] / libempathy-gtk / empathy-contact-blocking-dialog.c
1 /*
2  * empathy-contact-blocking-dialog.c
3  *
4  * EmpathyContactBlockingDialog
5  *
6  * Copyright (C) 2011 Collabora Ltd.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  * Authors: Danielle Madeley <danielle.madeley@collabora.co.uk>
23  */
24
25 #include <glib/gi18n.h>
26
27 #include <libempathy/empathy-utils.h>
28
29 #include <libempathy/empathy-contact-manager.h>
30 #include <libempathy/empathy-tp-contact-list.h>
31
32 #include <libempathy-gtk/empathy-account-chooser.h>
33 #include <libempathy-gtk/empathy-ui-utils.h>
34
35 #include "empathy-contact-blocking-dialog.h"
36
37 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
38 #include <libempathy/empathy-debug.h>
39
40 #define GET_PRIVATE(o) (EMPATHY_CONTACT_BLOCKING_DIALOG (o)->priv)
41 #define DECLARE_CALLBACK(func) \
42   static void func (GObject *, GAsyncResult *, gpointer);
43
44 G_DEFINE_TYPE (EmpathyContactBlockingDialog, empathy_contact_blocking_dialog,
45     GTK_TYPE_DIALOG);
46
47 struct _EmpathyContactBlockingDialogPrivate
48 {
49   /* a map of all active connections to their 'deny' channel */
50   GHashTable *channels; /* reffed TpConnection* -> reffed TpChannel* */
51
52   guint block_account_changed;
53
54   GtkListStore *blocked_contacts;
55   GtkListStore *completion_contacts;
56   GtkTreeSelection *selection;
57
58   GtkWidget *account_chooser;
59   GtkWidget *add_button;
60   GtkWidget *add_contact_entry;
61   GtkWidget *remove_button;
62 };
63
64 enum /* blocked-contacts columns */
65 {
66   COL_IDENTIFIER,
67   COL_HANDLE,
68   N_COLUMNS
69 };
70
71 static const char *
72 get_pretty_conn_name (TpConnection *conn)
73 {
74   return tp_proxy_get_object_path (conn) + strlen (TP_CONN_OBJECT_PATH_BASE);
75 }
76
77 static void
78 contact_blocking_dialog_filter_account_chooser (TpAccount *account,
79     EmpathyAccountChooserFilterResultCallback callback,
80     gpointer callback_data,
81     gpointer user_data)
82 {
83   EmpathyContactBlockingDialog *self = user_data;
84   TpConnection *conn = tp_account_get_connection (account);
85   gboolean enable;
86
87   enable =
88     conn != NULL &&
89     g_hash_table_lookup (self->priv->channels, conn) != NULL;
90
91   callback (enable, callback_data);
92 }
93
94 static void contact_blocking_dialog_account_changed (GtkWidget *,
95     EmpathyContactBlockingDialog *);
96
97 static void
98 contact_blocking_dialog_refilter_account_chooser (
99     EmpathyContactBlockingDialog *self)
100 {
101   EmpathyAccountChooser *chooser =
102     EMPATHY_ACCOUNT_CHOOSER (self->priv->account_chooser);
103   TpConnection *conn;
104   gboolean enabled;
105
106   DEBUG ("Refiltering account chooser");
107
108   /* set the filter to refilter the account chooser */
109   self->priv->block_account_changed++;
110   empathy_account_chooser_set_filter (chooser,
111       contact_blocking_dialog_filter_account_chooser, self);
112   self->priv->block_account_changed--;
113
114   conn = empathy_account_chooser_get_connection (chooser);
115   enabled = (empathy_account_chooser_get_account (chooser) != NULL &&
116              conn != NULL &&
117              g_hash_table_lookup (self->priv->channels, conn) != NULL);
118
119   if (!enabled)
120     DEBUG ("No account selected");
121
122   gtk_widget_set_sensitive (self->priv->add_button, enabled);
123   gtk_widget_set_sensitive (self->priv->add_contact_entry, enabled);
124
125   contact_blocking_dialog_account_changed (self->priv->account_chooser, self);
126 }
127
128 static void contact_blocking_dialog_inspected_handles (TpConnection *,
129     const char **, const GError *, gpointer, GObject *);
130
131 static void
132 contact_blocking_dialog_add_contacts_to_list (
133     EmpathyContactBlockingDialog *self,
134     TpConnection *conn,
135     GArray *handles)
136 {
137   if (handles->len > 0)
138     tp_cli_connection_call_inspect_handles (conn, -1,
139         TP_HANDLE_TYPE_CONTACT, handles,
140         contact_blocking_dialog_inspected_handles,
141         g_boxed_copy (DBUS_TYPE_G_UINT_ARRAY, handles),
142         (GDestroyNotify) g_array_unref, G_OBJECT (self));
143 }
144
145 static void
146 contact_blocking_dialog_inspected_handles (TpConnection *conn,
147     const char **identifiers,
148     const GError *in_error,
149     gpointer user_data,
150     GObject *self)
151 {
152   EmpathyContactBlockingDialogPrivate *priv = GET_PRIVATE (self);
153   GArray *handles = user_data;
154   guint i;
155
156   if (in_error != NULL)
157     {
158       DEBUG ("Failed to inspect handles: %s", in_error->message);
159       return;
160     }
161
162   DEBUG ("Adding %u identifiers", handles->len);
163
164   for (i = 0; i < handles->len; i++)
165     {
166       const char *identifier = identifiers[i];
167       TpHandle handle = g_array_index (handles, TpHandle, i);
168
169       gtk_list_store_insert_with_values (priv->blocked_contacts, NULL, -1,
170           COL_IDENTIFIER, identifier,
171           COL_HANDLE, handle,
172           -1);
173     }
174 }
175
176 DECLARE_CALLBACK (contact_blocking_dialog_connection_prepared);
177
178 static void
179 contact_blocking_dialog_connection_status_changed (TpAccount *account,
180     guint old_status,
181     guint new_status,
182     guint reason,
183     const char *dbus_reason,
184     GHashTable *details,
185     EmpathyContactBlockingDialog *self)
186 {
187   TpConnection *conn = tp_account_get_connection (account);
188
189   switch (new_status)
190     {
191       case TP_CONNECTION_STATUS_DISCONNECTED:
192         DEBUG ("Connection %s invalidated", get_pretty_conn_name (conn));
193
194         /* remove the channel from the hash table */
195         g_hash_table_remove (self->priv->channels, conn);
196         contact_blocking_dialog_refilter_account_chooser (self);
197         break;
198
199       case TP_CONNECTION_STATUS_CONNECTING:
200         break;
201
202       case TP_CONNECTION_STATUS_CONNECTED:
203         DEBUG ("Connection %s reconnected", get_pretty_conn_name (conn));
204
205         tp_proxy_prepare_async (conn, NULL,
206             contact_blocking_dialog_connection_prepared, self);
207     }
208 }
209
210 static void
211 contact_blocking_dialog_deny_channel_members_changed (TpChannel *channel,
212     const char *message,
213     GArray *added,
214     GArray *removed,
215     GArray *local_pending,
216     GArray *remote_pending,
217     TpHandle actor,
218     guint reason,
219     EmpathyContactBlockingDialog *self)
220 {
221   TpConnection *conn = tp_channel_borrow_connection (channel);
222   GtkTreeModel *model = GTK_TREE_MODEL (self->priv->blocked_contacts);
223   GtkTreeIter iter;
224   TpIntset *removed_set;
225   gboolean valid;
226
227   /* we only care about changes to the selected connection */
228   /* FIXME: can we compare proxy pointers directly? */
229   if (tp_strdiff (
230         tp_proxy_get_object_path (tp_channel_borrow_connection (channel)),
231         tp_proxy_get_object_path (empathy_account_chooser_get_connection (
232             EMPATHY_ACCOUNT_CHOOSER (self->priv->account_chooser)))))
233     return;
234
235   DEBUG ("deny list changed: %u added, %u removed", added->len, removed->len);
236
237   /* add contacts */
238   contact_blocking_dialog_add_contacts_to_list (self, conn, added);
239
240   /* remove contacts */
241   removed_set = tp_intset_from_array (removed);
242
243   valid = gtk_tree_model_get_iter_first (model, &iter);
244   while (valid)
245     {
246       TpHandle handle;
247
248       gtk_tree_model_get (model, &iter,
249           COL_HANDLE, &handle,
250           -1);
251
252       if (tp_intset_is_member (removed_set, handle))
253         valid = gtk_list_store_remove (self->priv->blocked_contacts, &iter);
254       else
255         valid = gtk_tree_model_iter_next (model, &iter);
256     }
257
258   tp_intset_destroy (removed_set);
259 }
260
261 DECLARE_CALLBACK (contact_blocking_dialog_connection_prepared);
262
263 static void
264 contact_blocking_dialog_am_prepared (GObject *am,
265     GAsyncResult *result,
266     gpointer user_data)
267 {
268   EmpathyContactBlockingDialog *self = user_data;
269   GList *accounts, *ptr;
270   GError *error = NULL;
271
272   if (!tp_proxy_prepare_finish (am, result, &error))
273     {
274       g_critical ("Could not prepare Account Manager: %s", error->message);
275       g_error_free (error);
276       return;
277     }
278
279   accounts = tp_account_manager_get_valid_accounts (TP_ACCOUNT_MANAGER (am));
280
281   for (ptr = accounts; ptr != NULL; ptr = ptr->next)
282     {
283       TpAccount *account = ptr->data;
284       TpConnection *conn;
285
286       g_signal_connect (account, "status-changed",
287           G_CALLBACK (contact_blocking_dialog_connection_status_changed), self);
288
289       conn = tp_account_get_connection (TP_ACCOUNT (account));
290
291       if (conn != NULL)
292         {
293           tp_proxy_prepare_async (conn, NULL,
294               contact_blocking_dialog_connection_prepared, self);
295         }
296     }
297
298   g_list_free (accounts);
299 }
300
301 static void contact_blocking_dialog_got_deny_channel (TpConnection *,
302     gboolean, const char *, GHashTable *, const GError *, gpointer, GObject *);
303
304 static void
305 contact_blocking_dialog_connection_prepared (GObject *conn,
306     GAsyncResult *result,
307     gpointer user_data)
308 {
309   EmpathyContactBlockingDialog *self = user_data;
310   GHashTable *request;
311   GError *error = NULL;
312
313   if (!tp_proxy_prepare_finish (conn, result, &error))
314     {
315       DEBUG ("Failed to prepare connection: %s", error->message);
316       g_error_free (error);
317       return;
318     }
319
320   /* request the deny channel */
321   request = tp_asv_new (
322       TP_PROP_CHANNEL_CHANNEL_TYPE,
323       G_TYPE_STRING,
324       TP_IFACE_CHANNEL_TYPE_CONTACT_LIST,
325
326       TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
327       G_TYPE_UINT,
328       TP_HANDLE_TYPE_LIST,
329
330       TP_PROP_CHANNEL_TARGET_ID,
331       G_TYPE_STRING,
332       "deny",
333
334       NULL);
335
336   tp_cli_connection_interface_requests_call_ensure_channel (
337       TP_CONNECTION (conn), -1, request,
338       contact_blocking_dialog_got_deny_channel, NULL, NULL, G_OBJECT (self));
339
340   g_hash_table_destroy (request);
341 }
342
343 DECLARE_CALLBACK (contact_blocking_dialog_deny_channel_prepared);
344
345 static void
346 contact_blocking_dialog_got_deny_channel (TpConnection *conn,
347     gboolean yours,
348     const char *channel_path,
349     GHashTable *props,
350     const GError *in_error,
351     gpointer user_data,
352     GObject *self)
353 {
354   TpChannel *channel;
355   GError *error = NULL;
356
357   const GQuark features[] = {
358       TP_CHANNEL_FEATURE_CORE,
359       TP_CHANNEL_FEATURE_GROUP,
360       0 };
361
362   if (in_error != NULL)
363     {
364       DEBUG ("Failed to get 'deny' channel: %s", in_error->message);
365       return;
366     }
367
368   channel = tp_channel_new_from_properties (conn, channel_path, props, &error);
369
370   if (error != NULL)
371     {
372       DEBUG ("Failed to create channel proxy: %s", error->message);
373       g_error_free (error);
374       return;
375     }
376
377   tp_proxy_prepare_async (channel, features,
378       contact_blocking_dialog_deny_channel_prepared, self);
379 }
380
381 static void
382 contact_blocking_dialog_deny_channel_prepared (GObject *channel,
383     GAsyncResult *result,
384     gpointer user_data)
385 {
386   EmpathyContactBlockingDialog *self = user_data;
387   TpConnection *conn;
388   GError *error = NULL;
389
390   if (!tp_proxy_prepare_finish (channel, result, &error))
391     {
392       DEBUG ("Failed to prepare channel: %s", error->message);
393       g_error_free (error);
394       return;
395     }
396
397   conn = tp_channel_borrow_connection (TP_CHANNEL (channel));
398
399   DEBUG ("Channel prepared for connection %s", get_pretty_conn_name (conn));
400
401   g_hash_table_insert (self->priv->channels,
402       g_object_ref (conn), channel);
403   contact_blocking_dialog_refilter_account_chooser (self);
404
405   g_signal_connect (channel, "group-members-changed",
406       G_CALLBACK (contact_blocking_dialog_deny_channel_members_changed), self);
407 }
408
409 static void contact_blocking_dialog_add_contact_got_handle (TpConnection *,
410     const GArray *, const GError *, gpointer, GObject *);
411
412 static void
413 contact_blocking_dialog_add_contact (GtkWidget *widget,
414     EmpathyContactBlockingDialog *self)
415 {
416   TpConnection *conn = empathy_account_chooser_get_connection (
417       EMPATHY_ACCOUNT_CHOOSER (self->priv->account_chooser));
418   const char *identifiers[2] = { NULL, };
419
420   identifiers[0] = gtk_entry_get_text (
421       GTK_ENTRY (self->priv->add_contact_entry));
422
423   DEBUG ("Looking up handle for '%s'", identifiers[0]);
424
425   tp_cli_connection_call_request_handles (conn, -1,
426       TP_HANDLE_TYPE_CONTACT, identifiers,
427       contact_blocking_dialog_add_contact_got_handle,
428       NULL, NULL, G_OBJECT (self));
429
430   gtk_entry_set_text (GTK_ENTRY (self->priv->add_contact_entry), "");
431 }
432
433 static void
434 contact_blocking_dialog_added_contact (TpChannel *, const GError *,
435     gpointer, GObject *);
436
437 static void
438 contact_blocking_dialog_add_contact_got_handle (TpConnection *conn,
439     const GArray *handles,
440     const GError *in_error,
441     gpointer user_data,
442     GObject *self)
443 {
444   EmpathyContactBlockingDialogPrivate *priv = GET_PRIVATE (self);
445   TpChannel *channel = g_hash_table_lookup (priv->channels, conn);
446
447   if (in_error != NULL)
448     {
449       DEBUG ("Error getting handle: %s", in_error->message);
450       /* FIXME: expose error to user */
451       return;
452     }
453
454   g_return_if_fail (handles->len == 1);
455
456   DEBUG ("Adding handle %u to deny channel",
457       g_array_index (handles, TpHandle, 0));
458
459   tp_cli_channel_interface_group_call_add_members (channel, -1,
460       handles, "",
461       contact_blocking_dialog_added_contact, NULL, NULL, self);
462 }
463
464 static void
465 contact_blocking_dialog_added_contact (TpChannel *channel,
466     const GError *in_error,
467     gpointer user_data,
468     GObject *self)
469 {
470   if (in_error != NULL)
471     {
472       DEBUG ("Error adding contact to deny list: %s", in_error->message);
473       /* FIXME: expose error to user */
474       return;
475     }
476
477   DEBUG ("Contact added");
478 }
479
480 static void
481 contact_blocking_dialog_removed_contacts (TpChannel *,
482     const GError *, gpointer, GObject *);
483
484 static void
485 contact_blocking_dialog_remove_contacts (GtkWidget *button,
486     EmpathyContactBlockingDialog *self)
487 {
488   TpConnection *conn = empathy_account_chooser_get_connection (
489       EMPATHY_ACCOUNT_CHOOSER (self->priv->account_chooser));
490   TpChannel *channel = g_hash_table_lookup (self->priv->channels, conn);
491   GtkTreeModel *model;
492   GList *rows, *ptr;
493   GArray *handles = g_array_new (FALSE, FALSE, sizeof (TpHandle));
494
495   rows = gtk_tree_selection_get_selected_rows (self->priv->selection, &model);
496
497   for (ptr = rows; ptr != NULL; ptr = ptr->next)
498     {
499       GtkTreePath *path = ptr->data;
500       GtkTreeIter iter;
501       TpHandle handle;
502
503       if (!gtk_tree_model_get_iter (model, &iter, path))
504         continue;
505
506       gtk_tree_model_get (model, &iter,
507           COL_HANDLE, &handle,
508           -1);
509
510       g_array_append_val (handles, handle);
511       gtk_tree_path_free (path);
512     }
513
514   g_list_free (rows);
515
516   if (handles->len > 0)
517     {
518       DEBUG ("Removing %u handles", handles->len);
519
520       tp_cli_channel_interface_group_call_remove_members (channel, -1,
521           handles, "",
522           contact_blocking_dialog_removed_contacts,
523           NULL, NULL, G_OBJECT (self));
524     }
525
526   g_array_unref (handles);
527 }
528
529 static void
530 contact_blocking_dialog_removed_contacts (TpChannel *channel,
531     const GError *in_error,
532     gpointer user_data,
533     GObject *self)
534 {
535   if (in_error != NULL)
536     {
537       DEBUG ("Error removing contacts from deny list: %s", in_error->message);
538       /* FIXME: expose error to user */
539       return;
540     }
541
542   DEBUG ("Contacts removed");
543 }
544
545 static void
546 contact_blocking_dialog_account_changed (GtkWidget *account_chooser,
547     EmpathyContactBlockingDialog *self)
548 {
549   TpConnection *conn = empathy_account_chooser_get_connection (
550       EMPATHY_ACCOUNT_CHOOSER (account_chooser));
551   TpChannel *channel;
552   GArray *blocked;
553   EmpathyContactManager *contact_manager;
554   EmpathyTpContactList *contact_list;
555   GList *members, *ptr;
556
557   if (self->priv->block_account_changed > 0)
558     return;
559
560   /* clear the lists of contacts */
561   gtk_list_store_clear (self->priv->blocked_contacts);
562   gtk_list_store_clear (self->priv->completion_contacts);
563
564   if (conn == NULL)
565     return;
566
567   DEBUG ("Account changed: %s", get_pretty_conn_name (conn));
568
569   /* load the deny list */
570   channel = g_hash_table_lookup (self->priv->channels, conn);
571
572   if (channel == NULL)
573     return;
574
575   g_return_if_fail (TP_IS_CHANNEL (channel));
576
577   blocked = tp_intset_to_array (tp_channel_group_get_members (channel));
578
579   DEBUG ("%u contacts on blocked list", blocked->len);
580
581   contact_blocking_dialog_add_contacts_to_list (self, conn, blocked);
582   g_array_unref (blocked);
583
584   /* load the completion list */
585   g_return_if_fail (empathy_contact_manager_initialized ());
586
587   DEBUG ("Loading contacts");
588
589   contact_manager = empathy_contact_manager_dup_singleton ();
590   contact_list = empathy_contact_manager_get_list (contact_manager, conn);
591   members = empathy_contact_list_get_members (
592       EMPATHY_CONTACT_LIST (contact_list));
593
594   for (ptr = members; ptr != NULL; ptr = ptr->next)
595     {
596       EmpathyContact *contact = ptr->data;
597
598       gtk_list_store_insert_with_values (self->priv->completion_contacts,
599           NULL, -1,
600           COL_IDENTIFIER, empathy_contact_get_id (contact),
601           -1);
602
603       g_object_unref (contact);
604     }
605
606   g_list_free (members);
607   g_object_unref (contact_manager);
608 }
609
610 static void
611 contact_blocking_dialog_view_selection_changed (GtkTreeSelection *selection,
612     EmpathyContactBlockingDialog *self)
613 {
614   GList *rows = gtk_tree_selection_get_selected_rows (selection, NULL);
615
616   /* update the sensitivity of the remove button */
617   gtk_widget_set_sensitive (self->priv->remove_button, rows != NULL);
618
619   g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
620   g_list_free (rows);
621 }
622
623 static void
624 contact_blocking_dialog_dispose (GObject *self)
625 {
626   EmpathyContactBlockingDialogPrivate *priv = GET_PRIVATE (self);
627
628   tp_clear_pointer (&priv->channels, g_hash_table_destroy);
629
630   G_OBJECT_CLASS (empathy_contact_blocking_dialog_parent_class)->dispose (self);
631 }
632
633 static void
634 empathy_contact_blocking_dialog_class_init (
635     EmpathyContactBlockingDialogClass *klass)
636 {
637   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
638
639   gobject_class->dispose = contact_blocking_dialog_dispose;
640
641   g_type_class_add_private (gobject_class,
642       sizeof (EmpathyContactBlockingDialogPrivate));
643 }
644
645 static void
646 empathy_contact_blocking_dialog_init (EmpathyContactBlockingDialog *self)
647 {
648   GtkBuilder *gui;
649   char *filename;
650   GtkWidget *contents;
651   GtkWidget *account_hbox, *blocked_contacts_view;
652   GtkEntryCompletion *completion;
653   TpAccountManager *am;
654
655   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
656       EMPATHY_TYPE_CONTACT_BLOCKING_DIALOG,
657       EmpathyContactBlockingDialogPrivate);
658
659   self->priv->channels = g_hash_table_new_full (NULL, NULL,
660       g_object_unref, g_object_unref);
661
662   gtk_window_set_title (GTK_WINDOW (self), _("Edit Blocked Contacts"));
663   gtk_dialog_add_button (GTK_DIALOG (self),
664       GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
665
666   filename = empathy_file_lookup ("empathy-contact-blocking-dialog.ui",
667       "libempathy-gtk");
668
669   gui = empathy_builder_get_file (filename,
670       "contents", &contents,
671       "account-hbox", &account_hbox,
672       "add-button", &self->priv->add_button,
673       "add-contact-entry", &self->priv->add_contact_entry,
674       "blocked-contacts", &self->priv->blocked_contacts,
675       "blocked-contacts-view", &blocked_contacts_view,
676       "remove-button", &self->priv->remove_button,
677       NULL);
678
679   empathy_builder_connect (gui, self,
680       "add-button", "clicked", contact_blocking_dialog_add_contact,
681       "add-contact-entry", "activate", contact_blocking_dialog_add_contact,
682       "remove-button", "clicked", contact_blocking_dialog_remove_contacts,
683       NULL);
684
685   /* add the contents to the dialog */
686   gtk_container_add (
687       GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (self))),
688       contents);
689   gtk_widget_show (contents);
690
691   /* set up the tree selection */
692   self->priv->selection = gtk_tree_view_get_selection (
693       GTK_TREE_VIEW (blocked_contacts_view));
694   gtk_tree_selection_set_mode (self->priv->selection, GTK_SELECTION_MULTIPLE);
695   g_signal_connect (self->priv->selection, "changed",
696       G_CALLBACK (contact_blocking_dialog_view_selection_changed), self);
697
698   /* build the contact entry */
699   self->priv->completion_contacts = gtk_list_store_new (1, G_TYPE_STRING);
700   completion = gtk_entry_completion_new ();
701   gtk_entry_completion_set_model (completion,
702       GTK_TREE_MODEL (self->priv->completion_contacts));
703   gtk_entry_completion_set_text_column (completion, COL_IDENTIFIER);
704   gtk_entry_set_completion (GTK_ENTRY (self->priv->add_contact_entry),
705       completion);
706   g_object_unref (completion);
707   g_object_unref (self->priv->completion_contacts);
708
709   /* add the account chooser */
710   self->priv->account_chooser = empathy_account_chooser_new ();
711   contact_blocking_dialog_refilter_account_chooser (self);
712   g_signal_connect (self->priv->account_chooser, "changed",
713       G_CALLBACK (contact_blocking_dialog_account_changed), self);
714
715   gtk_box_pack_start (GTK_BOX (account_hbox), self->priv->account_chooser,
716       TRUE, TRUE, 0);
717   gtk_widget_show (self->priv->account_chooser);
718
719   /* prepare the account manager */
720   am = tp_account_manager_dup ();
721   tp_proxy_prepare_async (am, NULL, contact_blocking_dialog_am_prepared, self);
722   g_object_unref (am);
723
724   g_free (filename);
725   g_object_unref (gui);
726 }
727
728 GtkWidget *
729 empathy_contact_blocking_dialog_new (GtkWindow *parent)
730 {
731   GtkWidget *self = g_object_new (EMPATHY_TYPE_CONTACT_BLOCKING_DIALOG,
732       NULL);
733
734   if (parent != NULL)
735     {
736       gtk_window_set_transient_for (GTK_WINDOW (self), parent);
737     }
738
739   return self;
740 }