]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-widget.c
e93117b3602f47c094d86c024295ce7cb006154a
[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 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program 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  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26 #include <stdlib.h>
27
28 #include <gtk/gtk.h>
29 #include <glade/glade.h>
30 #include <glib/gi18n.h>
31
32 #include <libmissioncontrol/mc-account.h>
33
34 #include <libempathy/empathy-contact-manager.h>
35
36 #include "empathy-contact-widget.h"
37 #include "gossip-account-chooser.h"
38 #include "gossip-ui-utils.h"
39
40 typedef struct {
41         GossipContact   *contact;
42         gboolean         is_user;
43         gboolean         editable;
44         gboolean         can_change_contact;
45         GtkCellRenderer *renderer;
46
47         GtkWidget       *vbox_contact_widget;
48
49         /* Contact */
50         GtkWidget       *vbox_contact;
51         GtkWidget       *widget_avatar;
52         GtkWidget       *widget_account;
53         GtkWidget       *widget_id;
54         GtkWidget       *widget_alias;
55         GtkWidget       *label_alias;
56         GtkWidget       *entry_alias;
57         GtkWidget       *hbox_presence;
58         GtkWidget       *image_state;
59         GtkWidget       *label_status;
60         GtkWidget       *table_contact;
61         GtkWidget       *hbox_contact;
62
63         /* Groups */
64         GtkWidget       *vbox_groups;
65         GtkWidget       *entry_group;
66         GtkWidget       *button_group;
67         GtkWidget       *treeview_groups;
68
69         /* Details */
70         GtkWidget       *vbox_details;
71         GtkWidget       *table_details;
72         GtkWidget       *hbox_details_requested;
73
74         /* Client */
75         GtkWidget       *vbox_client;
76         GtkWidget       *table_client;
77         GtkWidget       *hbow_client_requested;
78
79 } EmpathyContactWidget;
80
81 typedef struct {
82         EmpathyContactWidget *information;
83         const gchar          *name;
84         gboolean              found;
85         GtkTreeIter           found_iter;
86 } FindName;
87
88 static void     contact_widget_destroy_cb                 (GtkWidget             *widget,
89                                                            EmpathyContactWidget  *information);
90 static void     contact_widget_remove_contact             (EmpathyContactWidget  *information);
91 static void     contact_widget_set_contact                (EmpathyContactWidget  *information,
92                                                            GossipContact         *contact);
93 static void     contact_widget_contact_setup              (EmpathyContactWidget  *information);
94 static void     contact_widget_contact_update             (EmpathyContactWidget  *information);
95 static gboolean contact_widget_update_contact             (EmpathyContactWidget  *information);
96 static void     contact_widget_account_changed_cb         (GtkComboBox           *widget,
97                                                            EmpathyContactWidget  *information);
98 static gboolean contact_widget_id_focus_out_cb            (GtkWidget             *widget,
99                                                            GdkEventFocus         *event,
100                                                            EmpathyContactWidget  *information);
101 static gboolean contact_widget_entry_alias_focus_event_cb (GtkEditable           *editable,
102                                                            GdkEventFocus         *event,
103                                                            EmpathyContactWidget  *information);
104 static void     contact_widget_name_notify_cb             (EmpathyContactWidget  *information);
105 static void     contact_widget_presence_notify_cb         (EmpathyContactWidget  *information);
106 static void     contact_widget_avatar_notify_cb           (EmpathyContactWidget  *information);
107 static void     contact_widget_groups_setup               (EmpathyContactWidget  *information);
108 static void     contact_widget_groups_update              (EmpathyContactWidget  *information);
109 static void     contact_widget_model_setup                (EmpathyContactWidget  *information);
110 static void     contact_widget_model_populate_columns     (EmpathyContactWidget  *information);
111 static void     contact_widget_groups_populate_data       (EmpathyContactWidget  *information);
112 static void     contact_widget_groups_notify_cb           (EmpathyContactWidget  *information);
113 static gboolean contact_widget_model_find_name            (EmpathyContactWidget  *information,
114                                                            const gchar           *name,
115                                                            GtkTreeIter           *iter);
116 static gboolean contact_widget_model_find_name_foreach    (GtkTreeModel          *model,
117                                                            GtkTreePath           *path,
118                                                            GtkTreeIter           *iter,
119                                                            FindName              *data);
120 static void     contact_widget_cell_toggled               (GtkCellRendererToggle *cell,
121                                                            gchar                 *path_string,
122                                                            EmpathyContactWidget  *information);
123 static void     contact_widget_entry_group_changed_cb     (GtkEditable           *editable,
124                                                            EmpathyContactWidget  *information);
125 static void     contact_widget_entry_group_activate_cb    (GtkEntry              *entry,
126                                                            EmpathyContactWidget  *information);
127 static void     contact_widget_button_group_clicked_cb    (GtkButton             *button,
128                                                            EmpathyContactWidget  *information);
129 static void     contact_widget_details_setup              (EmpathyContactWidget  *information);
130 static void     contact_widget_details_update             (EmpathyContactWidget  *information);
131 static void     contact_widget_client_setup               (EmpathyContactWidget  *information);
132 static void     contact_widget_client_update              (EmpathyContactWidget  *information);
133
134 enum {
135         COL_NAME,
136         COL_ENABLED,
137         COL_EDITABLE,
138         COL_COUNT
139 };
140
141 GtkWidget *
142 empathy_contact_widget_new (GossipContact *contact,
143                             gboolean       editable)
144 {
145         EmpathyContactWidget *information;
146         GladeXML             *glade;
147
148         information = g_slice_new0 (EmpathyContactWidget);
149         information->editable = editable;
150         if (contact) {
151                 GossipContact *user_contact;
152         
153                 user_contact = gossip_contact_get_user (contact);
154                 information->is_user = gossip_contact_equal (contact, user_contact);
155                 information->can_change_contact = FALSE;
156         } else {
157                 information->is_user = FALSE;
158                 information->can_change_contact = TRUE;
159         }
160
161         glade = gossip_glade_get_file ("empathy-contact-widget.glade",
162                                        "vbox_contact_widget",
163                                        NULL,
164                                        "vbox_contact_widget", &information->vbox_contact_widget,
165                                        "vbox_contact", &information->vbox_contact,
166                                        "hbox_presence", &information->hbox_presence,
167                                        "label_alias", &information->label_alias,
168                                        "image_state", &information->image_state,
169                                        "label_status", &information->label_status,
170                                        "table_contact", &information->table_contact,
171                                        "hbox_contact", &information->hbox_contact,
172                                        "vbox_groups", &information->vbox_groups,
173                                        "entry_group", &information->entry_group,
174                                        "button_group", &information->button_group,
175                                        "treeview_groups", &information->treeview_groups,
176                                        "vbox_details", &information->vbox_details,
177                                        "table_details", &information->table_details,
178                                        "hbox_details_requested", &information->hbox_details_requested,
179                                        "vbox_client", &information->vbox_client,
180                                        "table_client", &information->table_client,
181                                        "hbox_client_requested", &information->hbow_client_requested,
182                                        NULL);
183
184         gossip_glade_connect (glade,
185                               information,
186                               "vbox_contact_widget", "destroy", contact_widget_destroy_cb,
187                               "entry_group", "changed", contact_widget_entry_group_changed_cb,
188                               "entry_group", "activate", contact_widget_entry_group_activate_cb,
189                               "button_group", "clicked", contact_widget_button_group_clicked_cb,
190                               NULL);
191
192         g_object_unref (glade);
193
194         g_object_set_data (G_OBJECT (information->vbox_contact_widget),
195                            "EmpathyContactWidget",
196                            information);
197
198         /* Create widgets */
199         contact_widget_contact_setup (information);
200         contact_widget_groups_setup (information);
201         contact_widget_details_setup (information);
202         contact_widget_client_setup (information);
203
204         contact_widget_set_contact (information, contact);
205
206         gtk_widget_show (information->vbox_contact_widget);
207
208         return information->vbox_contact_widget;
209 }
210
211 GossipContact *
212 empathy_contact_widget_get_contact (GtkWidget *widget)
213 {
214         EmpathyContactWidget *information;
215
216         g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
217
218         information = g_object_get_data (G_OBJECT (widget), "EmpathyContactWidget");
219         if (!information) {
220                 return NULL;
221         }
222
223         return information->contact;
224 }
225         
226 static void
227 contact_widget_destroy_cb (GtkWidget            *widget,
228                            EmpathyContactWidget *information)
229 {
230         contact_widget_remove_contact (information);
231         g_slice_free (EmpathyContactWidget, information);
232 }
233
234 static void
235 contact_widget_remove_contact (EmpathyContactWidget *information)
236 {
237         if (information->contact) {
238                 g_signal_handlers_disconnect_by_func (information->contact,
239                                                       contact_widget_name_notify_cb,
240                                                       information);
241                 g_signal_handlers_disconnect_by_func (information->contact,
242                                                       contact_widget_presence_notify_cb,
243                                                       information);
244                 g_signal_handlers_disconnect_by_func (information->contact,
245                                                       contact_widget_avatar_notify_cb,
246                                                       information);
247                 g_signal_handlers_disconnect_by_func (information->contact,
248                                                       contact_widget_groups_notify_cb,
249                                                       information);
250
251                 g_object_unref (information->contact);
252                 information->contact = NULL;
253         }
254 }
255
256 static void
257 contact_widget_set_contact (EmpathyContactWidget *information,
258                             GossipContact        *contact)
259 {
260         contact_widget_remove_contact (information);
261         if (contact) {
262                 information->contact = g_object_ref (contact);
263         }
264
265         /* Update information for widgets */
266         contact_widget_contact_update (information);
267         contact_widget_groups_update (information);
268         contact_widget_details_update (information);
269         contact_widget_client_update (information);
270 }
271
272 static void
273 contact_widget_contact_setup (EmpathyContactWidget *information)
274 {
275         /* FIXME: Use GossipAvatarImage if (editable && is_user)  */
276         information->widget_avatar = gtk_image_new ();
277         gtk_box_pack_end (GTK_BOX (information->hbox_contact),
278                           information->widget_avatar,
279                           FALSE, FALSE,
280                           6);
281
282         /* Setup account label/chooser */
283         if (information->can_change_contact) {
284                 information->widget_account = gossip_account_chooser_new ();
285                 g_signal_connect (information->widget_account, "changed",
286                                   G_CALLBACK (contact_widget_account_changed_cb),
287                                   information);
288         } else {
289                 information->widget_account = gtk_label_new (NULL);
290                 gtk_label_set_selectable (GTK_LABEL (information->widget_account), TRUE);
291         }
292         gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
293                                    information->widget_account,
294                                    1, 2, 0, 1);
295         gtk_widget_show (information->widget_account);
296
297         /* Setup id label/entry */
298         if (information->can_change_contact) {
299                 information->widget_id = gtk_entry_new ();
300                 g_signal_connect (information->widget_id, "focus-out-event",
301                                   G_CALLBACK (contact_widget_id_focus_out_cb),
302                                   information);
303         } else {
304                 information->widget_id = gtk_label_new (NULL);
305                 gtk_label_set_selectable (GTK_LABEL (information->widget_id), TRUE);
306         }
307         gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
308                                    information->widget_id,
309                                    1, 2, 1, 2);
310         gtk_widget_show (information->widget_id);
311
312         /* Setup alias label/entry */
313         if (information->editable) {
314                 information->widget_alias = gtk_entry_new ();
315                 g_signal_connect (information->widget_alias, "focus-out-event",
316                                   G_CALLBACK (contact_widget_entry_alias_focus_event_cb),
317                                   information);
318         } else {
319                 information->widget_alias = gtk_label_new (NULL);
320                 gtk_label_set_selectable (GTK_LABEL (information->widget_alias), TRUE);
321         }
322         gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
323                                    information->widget_alias,
324                                    1, 2, 2, 3);
325         gtk_widget_show (information->widget_alias);
326 }
327
328 static void
329 contact_widget_contact_update (EmpathyContactWidget *information)
330 {
331         McAccount   *account = NULL;
332         const gchar *id = NULL;
333
334         /* Connect and get info from new contact */
335         if (information->contact) {
336                 g_signal_connect_swapped (information->contact, "notify::name",
337                                           G_CALLBACK (contact_widget_name_notify_cb),
338                                           information);
339                 g_signal_connect_swapped (information->contact, "notify::presence",
340                                           G_CALLBACK (contact_widget_presence_notify_cb),
341                                           information);
342                 g_signal_connect_swapped (information->contact, "notify::avatar",
343                                           G_CALLBACK (contact_widget_avatar_notify_cb),
344                                           information);
345
346                 account = gossip_contact_get_account (information->contact);
347                 id = gossip_contact_get_id (information->contact);
348         }
349
350         /* Update account widget */
351         if (information->can_change_contact) {
352                 if (account) {
353                         g_signal_handlers_block_by_func (information->widget_account,
354                                                          contact_widget_account_changed_cb,
355                                                          information);
356                         gossip_account_chooser_set_account (GOSSIP_ACCOUNT_CHOOSER (information->widget_account),
357                                                             account);
358                         g_signal_handlers_unblock_by_func (information->widget_account,
359                                                            contact_widget_account_changed_cb,
360                                                            information);
361                 }
362         }
363         else if (account) {
364                 const gchar *name;
365
366                 name = mc_account_get_display_name (account);
367                 gtk_label_set_label (GTK_LABEL (information->widget_account), name);
368         }
369
370         /* Update id widget */
371         if (information->can_change_contact) {
372                 if (!G_STR_EMPTY (id)) {
373                         gtk_entry_set_text (GTK_ENTRY (information->widget_id), id);
374                 }
375         } else {
376                 gtk_label_set_label (GTK_LABEL (information->widget_id), id);
377         }
378
379         /* Update other widgets */
380         if (information->contact) {
381                 contact_widget_name_notify_cb (information);
382                 contact_widget_presence_notify_cb (information);
383                 contact_widget_avatar_notify_cb (information);
384
385                 gtk_widget_show (information->label_alias);
386                 gtk_widget_show (information->widget_alias);
387                 gtk_widget_show (information->hbox_presence);
388         } else {
389                 gtk_widget_hide (information->label_alias);
390                 gtk_widget_hide (information->widget_alias);
391                 gtk_widget_hide (information->hbox_presence);
392                 gtk_widget_hide (information->widget_avatar);
393         }
394 }
395
396 static gboolean
397 contact_widget_update_contact (EmpathyContactWidget *information)
398 {
399         McAccount   *account;
400         const gchar *id;
401
402         account = gossip_account_chooser_get_account (GOSSIP_ACCOUNT_CHOOSER (information->widget_account));
403         id = gtk_entry_get_text (GTK_ENTRY (information->widget_id));
404
405         if (account && !G_STR_EMPTY (id)) {
406                 EmpathyContactManager *manager;
407                 GossipContact         *contact;
408
409                 manager = empathy_contact_manager_new ();
410                 contact = empathy_contact_manager_create (manager, account, id);
411                 contact_widget_set_contact (information, contact);
412
413                 if (contact) {
414                         g_object_unref (contact);
415                 }
416                 g_object_unref (manager);
417         }
418
419         return FALSE;
420 }
421
422 static void
423 contact_widget_account_changed_cb (GtkComboBox          *widget,
424                                    EmpathyContactWidget *information)
425 {
426         contact_widget_update_contact (information);
427 }
428
429 static gboolean
430 contact_widget_id_focus_out_cb (GtkWidget            *widget,
431                                 GdkEventFocus        *event,
432                                 EmpathyContactWidget *information)
433 {
434         contact_widget_update_contact (information);
435         return FALSE;
436 }
437
438 static gboolean
439 contact_widget_entry_alias_focus_event_cb (GtkEditable          *editable,
440                                            GdkEventFocus        *event,
441                                            EmpathyContactWidget *information)
442 {
443         if (information->contact) {
444                 const gchar *name;
445
446                 name = gtk_entry_get_text (GTK_ENTRY (editable));
447                 gossip_contact_set_name (information->contact, name);
448         }
449
450         return FALSE;
451 }
452
453 static void
454 contact_widget_name_notify_cb (EmpathyContactWidget *information)
455 {
456         if (information->editable) {
457                 gtk_entry_set_text (GTK_ENTRY (information->widget_alias),
458                                     gossip_contact_get_name (information->contact));
459         } else {
460                 gtk_label_set_label (GTK_LABEL (information->widget_alias),
461                                      gossip_contact_get_name (information->contact));
462         }
463 }
464
465 static void
466 contact_widget_presence_notify_cb (EmpathyContactWidget *information)
467 {
468         gtk_label_set_text (GTK_LABEL (information->label_status),
469                             gossip_contact_get_status (information->contact));
470         gtk_image_set_from_icon_name (GTK_IMAGE (information->image_state),
471                                       gossip_icon_name_for_contact (information->contact),
472                                       GTK_ICON_SIZE_BUTTON);
473
474 }
475
476 static void
477 contact_widget_avatar_notify_cb (EmpathyContactWidget *information)
478 {
479         GdkPixbuf *avatar_pixbuf;
480
481         avatar_pixbuf = gossip_pixbuf_avatar_from_contact_scaled (information->contact,
482                                                                   48, 48);
483
484         if (avatar_pixbuf) {
485                 gtk_image_set_from_pixbuf (GTK_IMAGE (information->widget_avatar),
486                                            avatar_pixbuf);
487                 gtk_widget_show  (information->widget_avatar);
488                 g_object_unref (avatar_pixbuf);
489         } else {
490                 gtk_widget_hide  (information->widget_avatar);
491         }
492 }
493
494 static void
495 contact_widget_groups_setup (EmpathyContactWidget *information)
496 {
497         if (information->editable) {
498                 contact_widget_model_setup (information);
499         }
500 }
501
502 static void
503 contact_widget_groups_update (EmpathyContactWidget *information)
504 {
505         if (information->editable && information->contact) {
506                 g_signal_connect_swapped (information->contact, "notify::groups",
507                                           G_CALLBACK (contact_widget_groups_notify_cb),
508                                           information);
509                 contact_widget_groups_populate_data (information);
510
511                 gtk_widget_show (information->vbox_groups);
512         } else {
513                 gtk_widget_hide (information->vbox_groups);
514         }
515 }
516
517 static void
518 contact_widget_model_setup (EmpathyContactWidget *information)
519 {
520         GtkTreeView      *view;
521         GtkListStore     *store;
522         GtkTreeSelection *selection;
523
524         view = GTK_TREE_VIEW (information->treeview_groups);
525
526         store = gtk_list_store_new (COL_COUNT,
527                                     G_TYPE_STRING,   /* name */
528                                     G_TYPE_BOOLEAN,  /* enabled */
529                                     G_TYPE_BOOLEAN); /* editable */
530
531         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
532
533         selection = gtk_tree_view_get_selection (view);
534         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
535
536         contact_widget_model_populate_columns (information);
537
538         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
539                                               COL_NAME, GTK_SORT_ASCENDING);
540
541         g_object_unref (store);
542 }
543
544 static void
545 contact_widget_model_populate_columns (EmpathyContactWidget *information)
546 {
547         GtkTreeView       *view;
548         GtkTreeModel      *model;
549         GtkTreeViewColumn *column;
550         GtkCellRenderer   *renderer;
551         guint              col_offset;
552
553         view = GTK_TREE_VIEW (information->treeview_groups);
554         model = gtk_tree_view_get_model (view);
555
556         renderer = gtk_cell_renderer_toggle_new ();
557         g_signal_connect (renderer, "toggled",
558                           G_CALLBACK (contact_widget_cell_toggled),
559                           information);
560
561         column = gtk_tree_view_column_new_with_attributes (_("Select"), renderer,
562                                                            "active", COL_ENABLED,
563                                                            NULL);
564
565         gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
566         gtk_tree_view_column_set_fixed_width (column, 50);
567         gtk_tree_view_append_column (view, column);
568
569         renderer = gtk_cell_renderer_text_new ();
570         col_offset = gtk_tree_view_insert_column_with_attributes (view,
571                                                                   -1, _("Group"),
572                                                                   renderer,
573                                                                   "text", COL_NAME,
574                                                                   /* "editable", COL_EDITABLE, */
575                                                                   NULL);
576
577         g_object_set_data (G_OBJECT (renderer),
578                            "column", GINT_TO_POINTER (COL_NAME));
579
580         column = gtk_tree_view_get_column (view, col_offset - 1);
581         gtk_tree_view_column_set_sort_column_id (column, COL_NAME);
582         gtk_tree_view_column_set_resizable (column,FALSE);
583         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
584
585         if (information->renderer) {
586                 g_object_unref (information->renderer);
587         }
588
589         information->renderer = g_object_ref (renderer);
590 }
591
592 static void
593 contact_widget_groups_populate_data (EmpathyContactWidget *information)
594 {
595         EmpathyContactManager *manager;
596         GtkTreeView           *view;
597         GtkListStore          *store;
598         GtkTreeIter            iter;
599         GList                 *my_groups, *l;
600         GList                 *all_groups;
601
602         view = GTK_TREE_VIEW (information->treeview_groups);
603         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
604         gtk_list_store_clear (store);
605
606         manager = empathy_contact_manager_new ();
607         all_groups = empathy_contact_manager_get_groups (manager);
608         my_groups = gossip_contact_get_groups (information->contact);
609         g_object_unref (manager);
610
611         for (l = all_groups; l; l = l->next) {
612                 const gchar *group_str;
613                 gboolean     enabled;
614
615                 group_str = l->data;
616
617                 enabled = g_list_find_custom (my_groups,
618                                               group_str,
619                                               (GCompareFunc) strcmp) != NULL;
620
621                 gtk_list_store_append (store, &iter);
622                 gtk_list_store_set (store, &iter,
623                                     COL_NAME, group_str,
624                                     COL_EDITABLE, TRUE,
625                                     COL_ENABLED, enabled,
626                                     -1);
627         }
628
629         g_list_free (all_groups);
630 }
631
632 static void
633 contact_widget_groups_notify_cb (EmpathyContactWidget *information)
634 {
635         /* FIXME: not implemented */
636 }
637
638 static gboolean
639 contact_widget_model_find_name (EmpathyContactWidget *information,
640                                 const gchar          *name,
641                                 GtkTreeIter          *iter)
642 {
643         GtkTreeView  *view;
644         GtkTreeModel *model;
645         FindName      data;
646
647         if (G_STR_EMPTY (name)) {
648                 return FALSE;
649         }
650
651         data.information = information;
652         data.name = name;
653         data.found = FALSE;
654
655         view = GTK_TREE_VIEW (information->treeview_groups);
656         model = gtk_tree_view_get_model (view);
657
658         gtk_tree_model_foreach (model,
659                                 (GtkTreeModelForeachFunc) contact_widget_model_find_name_foreach,
660                                 &data);
661
662         if (data.found == TRUE) {
663                 *iter = data.found_iter;
664                 return TRUE;
665         }
666
667         return FALSE;
668 }
669
670 static gboolean
671 contact_widget_model_find_name_foreach (GtkTreeModel *model,
672                                         GtkTreePath  *path,
673                                         GtkTreeIter  *iter,
674                                         FindName     *data)
675 {
676         gchar *name;
677
678         gtk_tree_model_get (model, iter,
679                             COL_NAME, &name,
680                             -1);
681
682         if (!name) {
683                 return FALSE;
684         }
685
686         if (data->name && strcmp (data->name, name) == 0) {
687                 data->found = TRUE;
688                 data->found_iter = *iter;
689
690                 g_free (name);
691
692                 return TRUE;
693         }
694
695         g_free (name);
696
697         return FALSE;
698 }
699
700 static void
701 contact_widget_cell_toggled (GtkCellRendererToggle *cell,
702                              gchar                 *path_string,
703                              EmpathyContactWidget  *information)
704 {
705         GtkTreeView  *view;
706         GtkTreeModel *model;
707         GtkListStore *store;
708         GtkTreePath  *path;
709         GtkTreeIter   iter;
710         gboolean      enabled;
711         gchar        *group;
712
713         view = GTK_TREE_VIEW (information->treeview_groups);
714         model = gtk_tree_view_get_model (view);
715         store = GTK_LIST_STORE (model);
716
717         path = gtk_tree_path_new_from_string (path_string);
718
719         gtk_tree_model_get_iter (model, &iter, path);
720         gtk_tree_model_get (model, &iter,
721                             COL_ENABLED, &enabled,
722                             COL_NAME, &group,
723                             -1);
724
725         gtk_list_store_set (store, &iter, COL_ENABLED, !enabled, -1);
726         gtk_tree_path_free (path);
727
728         if (group) {
729                 if (enabled) {
730                         gossip_contact_remove_group (information->contact, group);
731                 } else {
732                         gossip_contact_add_group (information->contact, group); 
733                 }
734
735                 g_free (group);
736         }
737 }
738
739 static void
740 contact_widget_entry_group_changed_cb (GtkEditable           *editable,
741                                        EmpathyContactWidget  *information)
742 {
743         GtkTreeIter  iter;
744         const gchar *group;
745
746         group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
747
748         if (contact_widget_model_find_name (information, group, &iter)) {
749                 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group), FALSE);
750
751         } else {
752                 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group),
753                                           !G_STR_EMPTY (group));
754         }
755 }
756
757 static void
758 contact_widget_entry_group_activate_cb (GtkEntry              *entry,
759                                         EmpathyContactWidget  *information)
760 {
761         gtk_widget_activate (GTK_WIDGET (information->button_group));
762 }
763
764 static void
765 contact_widget_button_group_clicked_cb (GtkButton             *button,
766                                         EmpathyContactWidget  *information)
767 {
768         GtkTreeView  *view;
769         GtkListStore *store;
770         GtkTreeIter   iter;
771         const gchar  *group;
772
773         view = GTK_TREE_VIEW (information->treeview_groups);
774         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
775
776         group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
777
778         gtk_list_store_append (store, &iter);
779         gtk_list_store_set (store, &iter,
780                             COL_NAME, group,
781                             COL_ENABLED, TRUE,
782                             -1);
783
784         gossip_contact_add_group (information->contact, group);
785 }
786
787 static void
788 contact_widget_details_setup (EmpathyContactWidget *information)
789 {
790         /* FIXME: Needs new telepathy spec */
791         gtk_widget_hide (information->vbox_details);
792 }
793
794 static void
795 contact_widget_details_update (EmpathyContactWidget *information)
796 {
797         /* FIXME: Needs new telepathy spec */
798 }
799
800 static void
801 contact_widget_client_setup (EmpathyContactWidget *information)
802 {
803         /* FIXME: Needs new telepathy spec */
804         gtk_widget_hide (information->vbox_client);
805 }
806
807 static void
808 contact_widget_client_update (EmpathyContactWidget *information)
809 {
810         /* FIXME: Needs new telepathy spec */
811 }
812