]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-widget.c
Reorder header inclusions accordingly to the Telepathy coding style
[empathy.git] / libempathy-gtk / empathy-contact-widget.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007-2009 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include "config.h"
23 #include "empathy-contact-widget.h"
24
25 #include <glib/gi18n-lib.h>
26
27 #include "empathy-avatar-image.h"
28 #include "empathy-client-factory.h"
29 #include "empathy-groups-widget.h"
30 #include "empathy-string-parser.h"
31 #include "empathy-ui-utils.h"
32 #include "empathy-utils.h"
33
34 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
35 #include "empathy-debug.h"
36
37 /**
38  * SECTION:empathy-contact-widget
39  * @title:EmpathyContactWidget
40  * @short_description: A widget used to display and edit details about a contact
41  * @include: libempathy-empathy-contact-widget.h
42  *
43  * #EmpathyContactWidget is a widget which displays appropriate widgets
44  * with details about a contact, also allowing changing these details,
45  * if desired.
46  */
47
48 /**
49  * EmpathyContactWidget:
50  * @parent: parent object
51  *
52  * Widget which displays appropriate widgets with details about a contact,
53  * also allowing changing these details, if desired.
54  */
55
56 G_DEFINE_TYPE (EmpathyContactWidget, empathy_contact_widget, GTK_TYPE_BOX)
57
58 /* Delay before updating the widget when the id entry changed (seconds) */
59 #define ID_CHANGED_TIMEOUT 1
60
61 #define DATA_FIELD "contact-info-field"
62
63 struct _EmpathyContactWidgetPriv
64 {
65   EmpathyContact *contact;
66   guint widget_id_timeout;
67   gulong fav_sig_id;
68
69   /* Contact */
70   GtkWidget *widget_avatar;
71   GtkWidget *widget_account;
72   GtkWidget *image_account;
73   GtkWidget *label_account;
74   GtkWidget *widget_id;
75   GtkWidget *widget_alias;
76   GtkWidget *label_alias;
77   GtkWidget *hbox_presence;
78   GtkWidget *image_state;
79   GtkWidget *label_status;
80   GtkWidget *grid_contact;
81   GtkWidget *vbox_avatar;
82   GtkWidget *favourite_checkbox;
83   GtkWidget *label_details;
84   GtkWidget *label_left_account;
85
86   /* Groups */
87   GtkWidget *groups_widget;
88
89   /* Client */
90   GtkWidget *vbox_client;
91   GtkWidget *grid_client;
92   GtkWidget *hbox_client_requested;
93 };
94
95 typedef struct
96 {
97   EmpathyContactWidget *self;
98   const gchar *name;
99   gboolean found;
100   GtkTreeIter found_iter;
101 } FindName;
102
103 enum
104 {
105   COL_NAME,
106   COL_ENABLED,
107   COL_EDITABLE,
108   COL_COUNT
109 };
110
111
112 static void
113 contact_widget_client_update (EmpathyContactWidget *self)
114 {
115   /* FIXME: Needs new telepathy spec */
116 }
117
118 static void
119 contact_widget_client_setup (EmpathyContactWidget *self)
120 {
121   /* FIXME: Needs new telepathy spec */
122   gtk_widget_hide (self->priv->vbox_client);
123 }
124
125 static void
126 contact_widget_groups_update (EmpathyContactWidget *self)
127 {
128   if (self->priv->contact != NULL)
129     {
130       FolksPersona *persona =
131           empathy_contact_get_persona (self->priv->contact);
132
133       if (FOLKS_IS_GROUP_DETAILS (persona))
134         {
135           empathy_groups_widget_set_group_details (
136               EMPATHY_GROUPS_WIDGET (self->priv->groups_widget),
137               FOLKS_GROUP_DETAILS (persona));
138           gtk_widget_show (self->priv->groups_widget);
139
140           return;
141         }
142     }
143
144   /* In case of failure */
145   gtk_widget_hide (self->priv->groups_widget);
146 }
147
148 static void
149 save_avatar_menu_activate_cb (GtkWidget *widget,
150     EmpathyContactWidget *self)
151 {
152   GtkWidget *dialog;
153   EmpathyAvatar *avatar;
154   gchar *ext = NULL, *filename;
155
156   dialog = gtk_file_chooser_dialog_new (_("Save Avatar"),
157       NULL,
158       GTK_FILE_CHOOSER_ACTION_SAVE,
159       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
160       GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
161       NULL);
162
163   gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
164       TRUE);
165
166   /* look for the avatar extension */
167   avatar = empathy_contact_get_avatar (self->priv->contact);
168   if (avatar->format != NULL)
169     {
170       gchar **splitted;
171
172       splitted = g_strsplit (avatar->format, "/", 2);
173       if (splitted[0] != NULL && splitted[1] != NULL)
174           ext = g_strdup (splitted[1]);
175
176       g_strfreev (splitted);
177     }
178   else
179     {
180       /* Avatar was loaded from the cache so was converted to PNG */
181       ext = g_strdup ("png");
182     }
183
184   if (ext != NULL)
185     {
186       gchar *id;
187
188       id = tp_escape_as_identifier (empathy_contact_get_id (
189             self->priv->contact));
190
191       filename = g_strdup_printf ("%s.%s", id, ext);
192       gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename);
193
194       g_free (id);
195       g_free (ext);
196       g_free (filename);
197     }
198
199   if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
200     {
201       GError *error = NULL;
202
203       filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
204
205       if (!empathy_avatar_save_to_file (avatar, filename, &error))
206         {
207           /* Save error */
208           GtkWidget *error_dialog;
209
210           error_dialog = gtk_message_dialog_new (NULL, 0,
211               GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
212               _("Unable to save avatar"));
213
214           gtk_message_dialog_format_secondary_text (
215               GTK_MESSAGE_DIALOG (error_dialog), "%s", error->message);
216
217           g_signal_connect (error_dialog, "response",
218               G_CALLBACK (gtk_widget_destroy), NULL);
219
220           gtk_window_present (GTK_WINDOW (error_dialog));
221
222           g_clear_error (&error);
223         }
224
225       g_free (filename);
226     }
227
228   gtk_widget_destroy (dialog);
229 }
230
231 static void
232 popup_avatar_menu (EmpathyContactWidget *self,
233                    GtkWidget *parent,
234                    GdkEventButton *event)
235 {
236   GtkWidget *menu, *item;
237   gint button, event_time;
238
239   if (self->priv->contact == NULL ||
240       empathy_contact_get_avatar (self->priv->contact) == NULL)
241       return;
242
243   menu = empathy_context_menu_new (parent);
244
245   /* Add "Save as..." entry */
246   item = gtk_image_menu_item_new_from_stock (GTK_STOCK_SAVE_AS, NULL);
247   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
248   gtk_widget_show (item);
249
250   g_signal_connect (item, "activate",
251       G_CALLBACK (save_avatar_menu_activate_cb), self);
252
253   if (event)
254     {
255       button = event->button;
256       event_time = event->time;
257     }
258   else
259     {
260       button = 0;
261       event_time = gtk_get_current_event_time ();
262     }
263
264   gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
265       button, event_time);
266 }
267
268 static gboolean
269 widget_avatar_popup_menu_cb (GtkWidget *widget,
270                              EmpathyContactWidget *self)
271 {
272   popup_avatar_menu (self, widget, NULL);
273
274   return TRUE;
275 }
276
277 static gboolean
278 widget_avatar_button_press_event_cb (GtkWidget *widget,
279                                      GdkEventButton *event,
280                                      EmpathyContactWidget *self)
281 {
282   /* Ignore double-clicks and triple-clicks */
283   if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
284     {
285       popup_avatar_menu (self, widget, event);
286       return TRUE;
287     }
288
289   return FALSE;
290 }
291
292 static void
293 set_nickname_cb (GObject *source,
294     GAsyncResult *res,
295     gpointer user_data)
296 {
297   GError *error = NULL;
298
299   if (!tp_account_set_nickname_finish (TP_ACCOUNT (source), res, &error))
300     {
301       DEBUG ("Failed to set Account.Nickname: %s", error->message);
302       g_error_free (error);
303     }
304 }
305
306 static gboolean
307 contact_widget_entry_alias_focus_event_cb (GtkEditable *editable,
308     GdkEventFocus *event,
309     EmpathyContactWidget *self)
310 {
311   if (self->priv->contact)
312     {
313       const gchar *alias;
314
315       alias = gtk_entry_get_text (GTK_ENTRY (editable));
316
317       if (empathy_contact_is_user (self->priv->contact))
318         {
319           TpAccount * account;
320           const gchar *current_nickname;
321
322           account = empathy_contact_get_account (self->priv->contact);
323           current_nickname = tp_account_get_nickname (account);
324
325           if (tp_strdiff (current_nickname, alias))
326             {
327               DEBUG ("Set Account.Nickname to %s", alias);
328
329               tp_account_set_nickname_async (account, alias, set_nickname_cb,
330                   NULL);
331             }
332         }
333       else
334         {
335           empathy_contact_set_alias (self->priv->contact, alias);
336         }
337     }
338
339   return FALSE;
340 }
341
342 static void
343 contact_widget_name_notify_cb (EmpathyContactWidget *self)
344 {
345   if (GTK_IS_ENTRY (self->priv->widget_alias))
346       gtk_entry_set_text (GTK_ENTRY (self->priv->widget_alias),
347           empathy_contact_get_alias (self->priv->contact));
348   else
349       gtk_label_set_label (GTK_LABEL (self->priv->widget_alias),
350           empathy_contact_get_alias (self->priv->contact));
351 }
352
353 static void
354 contact_widget_presence_notify_cb (EmpathyContactWidget *self)
355 {
356   const gchar *status;
357   gchar *markup_text = NULL;
358
359   status = empathy_contact_get_status (self->priv->contact);
360   if (status != NULL)
361     markup_text = empathy_add_link_markup (status);
362   gtk_label_set_markup (GTK_LABEL (self->priv->label_status), markup_text);
363   g_free (markup_text);
364
365   gtk_image_set_from_icon_name (GTK_IMAGE (self->priv->image_state),
366       empathy_icon_name_for_contact (self->priv->contact),
367       GTK_ICON_SIZE_BUTTON);
368   gtk_widget_show (self->priv->image_state);
369 }
370
371 static void
372 contact_widget_remove_contact (EmpathyContactWidget *self)
373 {
374   if (self->priv->contact)
375     {
376       g_signal_handlers_disconnect_by_func (self->priv->contact,
377           contact_widget_name_notify_cb, self);
378       g_signal_handlers_disconnect_by_func (self->priv->contact,
379           contact_widget_presence_notify_cb, self);
380
381       g_object_unref (self->priv->contact);
382       self->priv->contact = NULL;
383     }
384 }
385
386 static void contact_widget_change_contact (EmpathyContactWidget *self);
387
388 static void
389 contact_widget_contact_update (EmpathyContactWidget *self)
390 {
391   TpAccount *account = NULL;
392   const gchar *id = NULL;
393
394   /* Connect and get info from new contact */
395   if (self->priv->contact)
396     {
397       g_signal_connect_swapped (self->priv->contact, "notify::name",
398           G_CALLBACK (contact_widget_name_notify_cb), self);
399       g_signal_connect_swapped (self->priv->contact, "notify::presence",
400           G_CALLBACK (contact_widget_presence_notify_cb), self);
401       g_signal_connect_swapped (self->priv->contact,
402           "notify::presence-message",
403           G_CALLBACK (contact_widget_presence_notify_cb), self);
404
405       account = empathy_contact_get_account (self->priv->contact);
406       id = empathy_contact_get_id (self->priv->contact);
407     }
408
409   /* Update account widget */
410   if (account)
411     {
412       g_signal_handlers_block_by_func (self->priv->widget_account,
413                contact_widget_change_contact,
414                self);
415       empathy_account_chooser_set_account (
416           EMPATHY_ACCOUNT_CHOOSER (self->priv->widget_account), account);
417       g_signal_handlers_unblock_by_func (self->priv->widget_account,
418           contact_widget_change_contact, self);
419     }
420
421   /* Update id widget */
422   gtk_entry_set_text (GTK_ENTRY (self->priv->widget_id), id ? id : "");
423
424   /* Update other widgets */
425   if (self->priv->contact)
426     {
427       contact_widget_name_notify_cb (self);
428       contact_widget_presence_notify_cb (self);
429
430       gtk_widget_show (self->priv->label_alias);
431       gtk_widget_show (self->priv->widget_alias);
432       gtk_widget_show (self->priv->widget_avatar);
433
434       gtk_widget_set_visible (self->priv->hbox_presence, TRUE);
435     }
436   else
437     {
438       gtk_widget_hide (self->priv->label_alias);
439       gtk_widget_hide (self->priv->widget_alias);
440       gtk_widget_hide (self->priv->hbox_presence);
441       gtk_widget_hide (self->priv->widget_avatar);
442     }
443 }
444
445 static void
446 contact_widget_set_contact (EmpathyContactWidget *self,
447                             EmpathyContact *contact)
448 {
449   if (contact == self->priv->contact)
450     return;
451
452   contact_widget_remove_contact (self);
453   if (contact)
454     self->priv->contact = g_object_ref (contact);
455
456   /* set the selected account to be the account this contact came from */
457   if (contact && EMPATHY_IS_ACCOUNT_CHOOSER (self->priv->widget_account)) {
458       empathy_account_chooser_set_account (
459                       EMPATHY_ACCOUNT_CHOOSER (self->priv->widget_account),
460                       empathy_contact_get_account (contact));
461   }
462
463   /* Update self for widgets */
464   contact_widget_contact_update (self);
465   contact_widget_groups_update (self);
466   contact_widget_client_update (self);
467 }
468
469 static void
470 contact_widget_got_contact_cb (GObject *source,
471     GAsyncResult *result,
472     gpointer user_data)
473 {
474   EmpathyContactWidget *self = user_data;
475   GError *error = NULL;
476   EmpathyContact *contact;
477
478   contact = empathy_client_factory_dup_contact_by_id_finish (
479       EMPATHY_CLIENT_FACTORY (source), result, &error);
480
481   if (contact == NULL)
482     {
483       DEBUG ("Error: %s", error->message);
484       g_error_free (error);
485       goto out;
486     }
487
488   contact_widget_set_contact (self, contact);
489
490   g_object_unref (contact);
491 out:
492   g_object_unref (self);
493 }
494
495 static void
496 contact_widget_change_contact (EmpathyContactWidget *self)
497 {
498   TpConnection *connection;
499   const gchar *id;
500
501   connection = empathy_account_chooser_get_connection (
502       EMPATHY_ACCOUNT_CHOOSER (self->priv->widget_account));
503   if (!connection)
504       return;
505
506   id = gtk_entry_get_text (GTK_ENTRY (self->priv->widget_id));
507   if (!EMP_STR_EMPTY (id))
508     {
509       EmpathyClientFactory *factory;
510
511       factory = empathy_client_factory_dup ();
512
513       empathy_client_factory_dup_contact_by_id_async (factory, connection,
514           id, contact_widget_got_contact_cb, g_object_ref (self));
515
516       g_object_unref (factory);
517     }
518 }
519
520 static gboolean
521 contact_widget_id_activate_timeout (EmpathyContactWidget *self)
522 {
523   contact_widget_change_contact (self);
524   return FALSE;
525 }
526
527 static void
528 contact_widget_id_changed_cb (GtkEntry *entry,
529                               EmpathyContactWidget *self)
530 {
531   if (self->priv->widget_id_timeout != 0)
532     {
533       g_source_remove (self->priv->widget_id_timeout);
534     }
535
536   self->priv->widget_id_timeout =
537     g_timeout_add_seconds (ID_CHANGED_TIMEOUT,
538         (GSourceFunc) contact_widget_id_activate_timeout, self);
539 }
540
541 static gboolean
542 contact_widget_id_focus_out_cb (GtkWidget *widget,
543                                 GdkEventFocus *event,
544                                 EmpathyContactWidget *self)
545 {
546   contact_widget_change_contact (self);
547   return FALSE;
548 }
549
550 static void
551 contact_widget_contact_setup (EmpathyContactWidget *self)
552 {
553   self->priv->label_status = gtk_label_new ("");
554   gtk_label_set_line_wrap_mode (GTK_LABEL (self->priv->label_status),
555                                 PANGO_WRAP_WORD_CHAR);
556   gtk_label_set_line_wrap (GTK_LABEL (self->priv->label_status),
557                            TRUE);
558   gtk_misc_set_alignment (GTK_MISC (self->priv->label_status), 0, 0.5);
559
560   gtk_label_set_selectable (GTK_LABEL (self->priv->label_status), TRUE);
561
562   gtk_box_pack_start (GTK_BOX (self->priv->hbox_presence),
563         self->priv->label_status, TRUE, TRUE, 0);
564   gtk_widget_show (self->priv->label_status);
565
566   /* Setup account chooser */
567   self->priv->widget_account = empathy_account_chooser_new ();
568   g_signal_connect_swapped (self->priv->widget_account, "changed",
569         G_CALLBACK (contact_widget_change_contact),
570         self);
571   gtk_grid_attach (GTK_GRID (self->priv->grid_contact),
572       self->priv->widget_account,
573       2, 0, 1, 1);
574   gtk_widget_show (self->priv->widget_account);
575
576   /* Set up avatar display */
577   self->priv->widget_avatar = empathy_avatar_image_new ();
578
579   g_signal_connect (self->priv->widget_avatar, "popup-menu",
580       G_CALLBACK (widget_avatar_popup_menu_cb), self);
581   g_signal_connect (self->priv->widget_avatar, "button-press-event",
582       G_CALLBACK (widget_avatar_button_press_event_cb), self);
583   gtk_box_pack_start (GTK_BOX (self->priv->vbox_avatar),
584           self->priv->widget_avatar,
585           FALSE, FALSE,
586           6);
587   gtk_widget_show (self->priv->widget_avatar);
588
589   /* Setup id entry */
590   self->priv->widget_id = gtk_entry_new ();
591   g_signal_connect (self->priv->widget_id, "focus-out-event",
592         G_CALLBACK (contact_widget_id_focus_out_cb),
593         self);
594   g_signal_connect (self->priv->widget_id, "changed",
595         G_CALLBACK (contact_widget_id_changed_cb),
596         self);
597   gtk_grid_attach (GTK_GRID (self->priv->grid_contact), self->priv->widget_id,
598       2, 1, 1, 1);
599   gtk_widget_set_hexpand (self->priv->widget_id, TRUE);
600
601   gtk_widget_show (self->priv->widget_id);
602
603   /* Setup alias entry */
604   self->priv->widget_alias = gtk_entry_new ();
605
606   g_signal_connect (self->priv->widget_alias, "focus-out-event",
607         G_CALLBACK (contact_widget_entry_alias_focus_event_cb),
608         self);
609
610   /* Make return activate the window default (the Close button) */
611   gtk_entry_set_activates_default (GTK_ENTRY (self->priv->widget_alias),
612       TRUE);
613
614   gtk_grid_attach (GTK_GRID (self->priv->grid_contact),
615       self->priv->widget_alias, 2, 2, 1, 1);
616   gtk_widget_set_hexpand (self->priv->widget_alias, TRUE);
617
618   gtk_label_set_selectable (GTK_LABEL (self->priv->label_status), FALSE);
619   gtk_widget_show (self->priv->widget_alias);
620 }
621
622 static void
623 empathy_contact_widget_finalize (GObject *object)
624 {
625   EmpathyContactWidget *self = EMPATHY_CONTACT_WIDGET (object);
626   void (*chain_up) (GObject *) =
627       ((GObjectClass *) empathy_contact_widget_parent_class)->finalize;
628
629   contact_widget_remove_contact (self);
630
631   if (self->priv->widget_id_timeout != 0)
632     {
633       g_source_remove (self->priv->widget_id_timeout);
634     }
635
636
637   if (chain_up != NULL)
638     chain_up (object);
639 }
640
641 /**
642  * empathy_contact_widget_new:
643  * @contact: an #EmpathyContact
644  *
645  * Creates a new #EmpathyContactWidget.
646  *
647  * Return value: a new #EmpathyContactWidget
648  */
649 GtkWidget *
650 empathy_contact_widget_new (EmpathyContact *contact)
651 {
652   EmpathyContactWidget *self;
653   gchar *filename;
654   GtkWidget *main_vbox;
655   GtkBuilder *gui;
656
657   g_return_val_if_fail (contact == NULL || EMPATHY_IS_CONTACT (contact), NULL);
658
659   self = g_object_new (EMPATHY_TYPE_CONTACT_WIDGET, NULL);
660
661   filename = empathy_file_lookup ("empathy-contact-widget.ui",
662       "libempathy-gtk");
663   gui = empathy_builder_get_file (filename,
664        "vbox_contact_widget", &main_vbox,
665        "hbox_presence", &self->priv->hbox_presence,
666        "label_alias", &self->priv->label_alias,
667        "image_state", &self->priv->image_state,
668        "grid_contact", &self->priv->grid_contact,
669        "vbox_avatar", &self->priv->vbox_avatar,
670        "groups_widget", &self->priv->groups_widget,
671        "vbox_client", &self->priv->vbox_client,
672        "grid_client", &self->priv->grid_client,
673        "hbox_client_requested", &self->priv->hbox_client_requested,
674        "label_details", &self->priv->label_details,
675        "label_left_account", &self->priv->label_left_account,
676        NULL);
677   g_free (filename);
678
679   gtk_container_add (GTK_CONTAINER (self), main_vbox);
680   gtk_widget_show (GTK_WIDGET (main_vbox));
681
682   /* Create widgets */
683   contact_widget_contact_setup (self);
684   contact_widget_client_setup (self);
685
686   gtk_widget_hide (self->priv->label_details);
687
688   if (contact != NULL)
689     contact_widget_set_contact (self, contact);
690   else
691     contact_widget_change_contact (self);
692
693   g_object_unref (gui);
694
695   return GTK_WIDGET (self);
696 }
697
698 /**
699  * empathy_contact_widget_get_contact:
700  * @widget: an #EmpathyContactWidget
701  *
702  * Get the #EmpathyContact related with the #EmpathyContactWidget @widget.
703  *
704  * Returns: the #EmpathyContact associated with @widget
705  */
706 EmpathyContact *
707 empathy_contact_widget_get_contact (GtkWidget *widget)
708 {
709   EmpathyContactWidget *self = EMPATHY_CONTACT_WIDGET (widget);
710
711   return self->priv->contact;
712 }
713
714 const gchar *
715 empathy_contact_widget_get_alias (GtkWidget *widget)
716 {
717   EmpathyContactWidget *self = EMPATHY_CONTACT_WIDGET (widget);
718
719   return gtk_entry_get_text (GTK_ENTRY (self->priv->widget_alias));
720 }
721
722 /**
723  * empathy_contact_widget_set_contact:
724  * @widget: an #EmpathyContactWidget
725  * @contact: a different #EmpathyContact
726  *
727  * Change the #EmpathyContact related with the #EmpathyContactWidget @widget.
728  */
729 void
730 empathy_contact_widget_set_contact (GtkWidget *widget,
731                                     EmpathyContact *contact)
732 {
733   EmpathyContactWidget *self = EMPATHY_CONTACT_WIDGET (widget);
734
735   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
736
737   contact_widget_set_contact (self, contact);
738 }
739
740 /**
741  * empathy_contact_widget_set_account_filter:
742  * @widget: an #EmpathyContactWidget
743  * @filter: a #EmpathyAccountChooserFilterFunc
744  * @user_data: user data to pass to @filter, or %NULL
745  *
746  * Set a filter on the #EmpathyAccountChooser included in the
747  * #EmpathyContactWidget.
748  */
749 void
750 empathy_contact_widget_set_account_filter (
751     GtkWidget *widget,
752     EmpathyAccountChooserFilterFunc filter,
753     gpointer user_data)
754 {
755   EmpathyContactWidget *self = EMPATHY_CONTACT_WIDGET (widget);
756   EmpathyAccountChooser *chooser;
757
758   chooser = EMPATHY_ACCOUNT_CHOOSER (self->priv->widget_account);
759   if (chooser)
760       empathy_account_chooser_set_filter (chooser, filter, user_data);
761 }
762
763 static void
764 empathy_contact_widget_class_init (
765     EmpathyContactWidgetClass *klass)
766 {
767   GObjectClass *oclass = G_OBJECT_CLASS (klass);
768
769   oclass->finalize = empathy_contact_widget_finalize;
770
771   g_type_class_add_private (klass, sizeof (EmpathyContactWidgetPriv));
772 }
773
774 static void
775 empathy_contact_widget_init (EmpathyContactWidget *self)
776 {
777   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
778       EMPATHY_TYPE_CONTACT_WIDGET, EmpathyContactWidgetPriv);
779 }