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