]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-widget.c
5c8f6d3d881554fdbba6360d9882240ee3d3694a
[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, "local-xmpp") == 0) {
297                 /* We can't add accounts to a XMPP LL connection
298                  * FIXME: We should inspect the flags of the contact list group interface
299                  */
300                 g_object_unref (profile);
301                 return FALSE;
302         }
303
304         g_object_unref (profile);
305         return TRUE;
306 }
307
308 static gboolean
309 contact_widget_id_activate_timeout (EmpathyContactWidget *self)
310 {
311         contact_widget_update_contact (self);
312         return FALSE;
313 }
314
315 static void
316 contact_widget_id_changed_cb (GtkEntry             *entry,
317                               EmpathyContactWidget *self)
318 {
319         if (self->widget_id_timeout != 0) {             
320                 g_source_remove (self->widget_id_timeout);
321         }
322
323         self->widget_id_timeout =
324                 g_timeout_add (ID_CHANGED_TIMEOUT,
325                                (GSourceFunc) contact_widget_id_activate_timeout,
326                                self);
327 }
328
329 static void
330 contact_widget_contact_setup (EmpathyContactWidget *information)
331 {
332         /* FIXME: Use EmpathyAvatarImage if (editable && is_user)  */
333         information->widget_avatar = gtk_image_new ();
334         gtk_box_pack_end (GTK_BOX (information->hbox_contact),
335                           information->widget_avatar,
336                           FALSE, FALSE,
337                           6);
338
339         /* Setup account label/chooser */
340         if (information->type == CONTACT_WIDGET_TYPE_ADD) {
341                 information->widget_account = empathy_account_chooser_new ();
342                 empathy_account_chooser_set_filter (
343                         EMPATHY_ACCOUNT_CHOOSER (information->widget_account),
344                         contact_widget_can_add_contact_to_account,
345                         NULL);
346
347                 g_signal_connect (information->widget_account, "changed",
348                                   G_CALLBACK (contact_widget_account_changed_cb),
349                                   information);
350         } else {
351                 information->widget_account = gtk_label_new (NULL);
352                 gtk_label_set_selectable (GTK_LABEL (information->widget_account), TRUE);
353                 gtk_misc_set_alignment (GTK_MISC (information->widget_account), 0, 0.5);
354         }
355         gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
356                                    information->widget_account,
357                                    1, 2, 0, 1);
358         gtk_widget_show (information->widget_account);
359
360         /* Setup id label/entry */
361         if (information->type == CONTACT_WIDGET_TYPE_ADD) {
362                 information->widget_id = gtk_entry_new ();
363                 g_signal_connect (information->widget_id, "focus-out-event",
364                                   G_CALLBACK (contact_widget_id_focus_out_cb),
365                                   information);
366                 g_signal_connect (information->widget_id, "changed",
367                                   G_CALLBACK (contact_widget_id_changed_cb),
368                                   information);
369         } else {
370                 information->widget_id = gtk_label_new (NULL);
371                 gtk_label_set_selectable (GTK_LABEL (information->widget_id), TRUE);
372                 gtk_misc_set_alignment (GTK_MISC (information->widget_id), 0, 0.5);
373         }
374         gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
375                                    information->widget_id,
376                                    1, 2, 1, 2);
377         gtk_widget_show (information->widget_id);
378
379         /* Setup alias label/entry */
380         if (information->type > CONTACT_WIDGET_TYPE_SHOW) {
381                 information->widget_alias = gtk_entry_new ();
382                 g_signal_connect (information->widget_alias, "focus-out-event",
383                                   G_CALLBACK (contact_widget_entry_alias_focus_event_cb),
384                                   information);
385         } else {
386                 information->widget_alias = gtk_label_new (NULL);
387                 gtk_label_set_selectable (GTK_LABEL (information->widget_alias), TRUE);
388                 gtk_misc_set_alignment (GTK_MISC (information->widget_alias), 0, 0.5);
389         }
390         gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
391                                    information->widget_alias,
392                                    1, 2, 2, 3);
393         gtk_widget_show (information->widget_alias);
394 }
395
396 static void
397 contact_widget_contact_update (EmpathyContactWidget *information)
398 {
399         McAccount   *account = NULL;
400         const gchar *id = NULL;
401
402         /* Connect and get info from new contact */
403         if (information->contact) {
404                 g_signal_connect_swapped (information->contact, "notify::name",
405                                           G_CALLBACK (contact_widget_name_notify_cb),
406                                           information);
407                 g_signal_connect_swapped (information->contact, "notify::presence",
408                                           G_CALLBACK (contact_widget_presence_notify_cb),
409                                           information);
410                 g_signal_connect_swapped (information->contact, "notify::avatar",
411                                           G_CALLBACK (contact_widget_avatar_notify_cb),
412                                           information);
413
414                 account = empathy_contact_get_account (information->contact);
415                 id = empathy_contact_get_id (information->contact);
416         }
417
418         /* Update account widget */
419         if (information->type == CONTACT_WIDGET_TYPE_ADD) {
420                 if (account) {
421                         g_signal_handlers_block_by_func (information->widget_account,
422                                                          contact_widget_account_changed_cb,
423                                                          information);
424                         empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (information->widget_account),
425                                                             account);
426                         g_signal_handlers_unblock_by_func (information->widget_account,
427                                                            contact_widget_account_changed_cb,
428                                                            information);
429                 }
430                 if (!G_STR_EMPTY (id)) {
431                         gtk_entry_set_text (GTK_ENTRY (information->widget_id), id);
432                 }
433         } else {
434                 if (account) {
435                         const gchar *name;
436
437                         name = mc_account_get_display_name (account);
438                         gtk_label_set_label (GTK_LABEL (information->widget_account), name);
439                 }
440                 gtk_label_set_label (GTK_LABEL (information->widget_id), id);
441         }
442
443         /* Update other widgets */
444         if (information->contact) {
445                 contact_widget_name_notify_cb (information);
446                 contact_widget_presence_notify_cb (information);
447                 contact_widget_avatar_notify_cb (information);
448
449                 gtk_widget_show (information->label_alias);
450                 gtk_widget_show (information->widget_alias);
451                 gtk_widget_show (information->hbox_presence);
452         } else {
453                 gtk_widget_hide (information->label_alias);
454                 gtk_widget_hide (information->widget_alias);
455                 gtk_widget_hide (information->hbox_presence);
456                 gtk_widget_hide (information->widget_avatar);
457         }
458 }
459
460 static gboolean
461 contact_widget_update_contact (EmpathyContactWidget *information)
462 {
463         McAccount   *account;
464         const gchar *id;
465
466         account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (information->widget_account));
467         id = gtk_entry_get_text (GTK_ENTRY (information->widget_id));
468
469         if (account && !G_STR_EMPTY (id)) {
470                 EmpathyContactManager *manager;
471                 EmpathyContact         *contact;
472
473                 manager = empathy_contact_manager_new ();
474                 contact = empathy_contact_manager_create (manager, account, id);
475                 contact_widget_set_contact (information, contact);
476
477                 if (contact) {
478                         g_object_unref (contact);
479                 }
480                 g_object_unref (manager);
481         }
482
483         return FALSE;
484 }
485
486 static void
487 contact_widget_account_changed_cb (GtkComboBox          *widget,
488                                    EmpathyContactWidget *information)
489 {
490         contact_widget_update_contact (information);
491 }
492
493 static gboolean
494 contact_widget_id_focus_out_cb (GtkWidget            *widget,
495                                 GdkEventFocus        *event,
496                                 EmpathyContactWidget *information)
497 {
498         contact_widget_update_contact (information);
499         return FALSE;
500 }
501
502 static gboolean
503 contact_widget_entry_alias_focus_event_cb (GtkEditable          *editable,
504                                            GdkEventFocus        *event,
505                                            EmpathyContactWidget *information)
506 {
507         if (information->contact) {
508                 const gchar *name;
509
510                 name = gtk_entry_get_text (GTK_ENTRY (editable));
511                 empathy_contact_set_name (information->contact, name);
512         }
513
514         return FALSE;
515 }
516
517 static void
518 contact_widget_name_notify_cb (EmpathyContactWidget *information)
519 {
520         if (GTK_IS_ENTRY (information->widget_alias)) {
521                 gtk_entry_set_text (GTK_ENTRY (information->widget_alias),
522                                     empathy_contact_get_name (information->contact));
523         } else {
524                 gtk_label_set_label (GTK_LABEL (information->widget_alias),
525                                      empathy_contact_get_name (information->contact));
526         }
527 }
528
529 static void
530 contact_widget_presence_notify_cb (EmpathyContactWidget *information)
531 {
532         gtk_label_set_text (GTK_LABEL (information->label_status),
533                             empathy_contact_get_status (information->contact));
534         gtk_image_set_from_icon_name (GTK_IMAGE (information->image_state),
535                                       empathy_icon_name_for_contact (information->contact),
536                                       GTK_ICON_SIZE_BUTTON);
537
538 }
539
540 static void
541 contact_widget_avatar_notify_cb (EmpathyContactWidget *information)
542 {
543         GdkPixbuf *avatar_pixbuf;
544
545         avatar_pixbuf = empathy_pixbuf_avatar_from_contact_scaled (information->contact,
546                                                                   48, 48);
547
548         if (avatar_pixbuf) {
549                 gtk_image_set_from_pixbuf (GTK_IMAGE (information->widget_avatar),
550                                            avatar_pixbuf);
551                 gtk_widget_show  (information->widget_avatar);
552                 g_object_unref (avatar_pixbuf);
553         } else {
554                 gtk_widget_hide  (information->widget_avatar);
555         }
556 }
557
558 static void
559 contact_widget_groups_setup (EmpathyContactWidget *information)
560 {
561         if (information->type > CONTACT_WIDGET_TYPE_SHOW) {
562                 contact_widget_model_setup (information);
563         }
564 }
565
566 static void
567 contact_widget_groups_update (EmpathyContactWidget *information)
568 {
569         if (information->type > CONTACT_WIDGET_TYPE_SHOW &&
570             information->contact) {
571                 g_signal_connect_swapped (information->contact, "notify::groups",
572                                           G_CALLBACK (contact_widget_groups_notify_cb),
573                                           information);
574                 contact_widget_groups_populate_data (information);
575
576                 gtk_widget_show (information->vbox_groups);
577         } else {
578                 gtk_widget_hide (information->vbox_groups);
579         }
580 }
581
582 static void
583 contact_widget_model_setup (EmpathyContactWidget *information)
584 {
585         GtkTreeView      *view;
586         GtkListStore     *store;
587         GtkTreeSelection *selection;
588
589         view = GTK_TREE_VIEW (information->treeview_groups);
590
591         store = gtk_list_store_new (COL_COUNT,
592                                     G_TYPE_STRING,   /* name */
593                                     G_TYPE_BOOLEAN,  /* enabled */
594                                     G_TYPE_BOOLEAN); /* editable */
595
596         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
597
598         selection = gtk_tree_view_get_selection (view);
599         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
600
601         contact_widget_model_populate_columns (information);
602
603         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
604                                               COL_NAME, GTK_SORT_ASCENDING);
605
606         g_object_unref (store);
607 }
608
609 static void
610 contact_widget_model_populate_columns (EmpathyContactWidget *information)
611 {
612         GtkTreeView       *view;
613         GtkTreeModel      *model;
614         GtkTreeViewColumn *column;
615         GtkCellRenderer   *renderer;
616         guint              col_offset;
617
618         view = GTK_TREE_VIEW (information->treeview_groups);
619         model = gtk_tree_view_get_model (view);
620
621         renderer = gtk_cell_renderer_toggle_new ();
622         g_signal_connect (renderer, "toggled",
623                           G_CALLBACK (contact_widget_cell_toggled),
624                           information);
625
626         column = gtk_tree_view_column_new_with_attributes (_("Select"), renderer,
627                                                            "active", COL_ENABLED,
628                                                            NULL);
629
630         gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
631         gtk_tree_view_column_set_fixed_width (column, 50);
632         gtk_tree_view_append_column (view, column);
633
634         renderer = gtk_cell_renderer_text_new ();
635         col_offset = gtk_tree_view_insert_column_with_attributes (view,
636                                                                   -1, _("Group"),
637                                                                   renderer,
638                                                                   "text", COL_NAME,
639                                                                   /* "editable", COL_EDITABLE, */
640                                                                   NULL);
641
642         g_object_set_data (G_OBJECT (renderer),
643                            "column", GINT_TO_POINTER (COL_NAME));
644
645         column = gtk_tree_view_get_column (view, col_offset - 1);
646         gtk_tree_view_column_set_sort_column_id (column, COL_NAME);
647         gtk_tree_view_column_set_resizable (column,FALSE);
648         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
649
650         if (information->renderer) {
651                 g_object_unref (information->renderer);
652         }
653
654         information->renderer = g_object_ref (renderer);
655 }
656
657 static void
658 contact_widget_groups_populate_data (EmpathyContactWidget *information)
659 {
660         EmpathyContactManager *manager;
661         GtkTreeView           *view;
662         GtkListStore          *store;
663         GtkTreeIter            iter;
664         GList                 *my_groups, *l;
665         GList                 *all_groups;
666
667         view = GTK_TREE_VIEW (information->treeview_groups);
668         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
669         gtk_list_store_clear (store);
670
671         manager = empathy_contact_manager_new ();
672         all_groups = empathy_contact_manager_get_groups (manager);
673         my_groups = empathy_contact_get_groups (information->contact);
674         g_object_unref (manager);
675
676         for (l = all_groups; l; l = l->next) {
677                 const gchar *group_str;
678                 gboolean     enabled;
679
680                 group_str = l->data;
681
682                 enabled = g_list_find_custom (my_groups,
683                                               group_str,
684                                               (GCompareFunc) strcmp) != NULL;
685
686                 gtk_list_store_append (store, &iter);
687                 gtk_list_store_set (store, &iter,
688                                     COL_NAME, group_str,
689                                     COL_EDITABLE, TRUE,
690                                     COL_ENABLED, enabled,
691                                     -1);
692         }
693
694         g_list_free (all_groups);
695 }
696
697 static void
698 contact_widget_groups_notify_cb (EmpathyContactWidget *information)
699 {
700         /* FIXME: not implemented */
701 }
702
703 static gboolean
704 contact_widget_model_find_name (EmpathyContactWidget *information,
705                                 const gchar          *name,
706                                 GtkTreeIter          *iter)
707 {
708         GtkTreeView  *view;
709         GtkTreeModel *model;
710         FindName      data;
711
712         if (G_STR_EMPTY (name)) {
713                 return FALSE;
714         }
715
716         data.information = information;
717         data.name = name;
718         data.found = FALSE;
719
720         view = GTK_TREE_VIEW (information->treeview_groups);
721         model = gtk_tree_view_get_model (view);
722
723         gtk_tree_model_foreach (model,
724                                 (GtkTreeModelForeachFunc) contact_widget_model_find_name_foreach,
725                                 &data);
726
727         if (data.found == TRUE) {
728                 *iter = data.found_iter;
729                 return TRUE;
730         }
731
732         return FALSE;
733 }
734
735 static gboolean
736 contact_widget_model_find_name_foreach (GtkTreeModel *model,
737                                         GtkTreePath  *path,
738                                         GtkTreeIter  *iter,
739                                         FindName     *data)
740 {
741         gchar *name;
742
743         gtk_tree_model_get (model, iter,
744                             COL_NAME, &name,
745                             -1);
746
747         if (!name) {
748                 return FALSE;
749         }
750
751         if (data->name && strcmp (data->name, name) == 0) {
752                 data->found = TRUE;
753                 data->found_iter = *iter;
754
755                 g_free (name);
756
757                 return TRUE;
758         }
759
760         g_free (name);
761
762         return FALSE;
763 }
764
765 static void
766 contact_widget_cell_toggled (GtkCellRendererToggle *cell,
767                              gchar                 *path_string,
768                              EmpathyContactWidget  *information)
769 {
770         GtkTreeView  *view;
771         GtkTreeModel *model;
772         GtkListStore *store;
773         GtkTreePath  *path;
774         GtkTreeIter   iter;
775         gboolean      enabled;
776         gchar        *group;
777
778         view = GTK_TREE_VIEW (information->treeview_groups);
779         model = gtk_tree_view_get_model (view);
780         store = GTK_LIST_STORE (model);
781
782         path = gtk_tree_path_new_from_string (path_string);
783
784         gtk_tree_model_get_iter (model, &iter, path);
785         gtk_tree_model_get (model, &iter,
786                             COL_ENABLED, &enabled,
787                             COL_NAME, &group,
788                             -1);
789
790         gtk_list_store_set (store, &iter, COL_ENABLED, !enabled, -1);
791         gtk_tree_path_free (path);
792
793         if (group) {
794                 if (enabled) {
795                         empathy_contact_remove_group (information->contact, group);
796                 } else {
797                         empathy_contact_add_group (information->contact, group);        
798                 }
799
800                 g_free (group);
801         }
802 }
803
804 static void
805 contact_widget_entry_group_changed_cb (GtkEditable           *editable,
806                                        EmpathyContactWidget  *information)
807 {
808         GtkTreeIter  iter;
809         const gchar *group;
810
811         group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
812
813         if (contact_widget_model_find_name (information, group, &iter)) {
814                 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group), FALSE);
815
816         } else {
817                 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group),
818                                           !G_STR_EMPTY (group));
819         }
820 }
821
822 static void
823 contact_widget_entry_group_activate_cb (GtkEntry              *entry,
824                                         EmpathyContactWidget  *information)
825 {
826         gtk_widget_activate (GTK_WIDGET (information->button_group));
827 }
828
829 static void
830 contact_widget_button_group_clicked_cb (GtkButton             *button,
831                                         EmpathyContactWidget  *information)
832 {
833         GtkTreeView  *view;
834         GtkListStore *store;
835         GtkTreeIter   iter;
836         const gchar  *group;
837
838         view = GTK_TREE_VIEW (information->treeview_groups);
839         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
840
841         group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
842
843         gtk_list_store_append (store, &iter);
844         gtk_list_store_set (store, &iter,
845                             COL_NAME, group,
846                             COL_ENABLED, TRUE,
847                             -1);
848
849         empathy_contact_add_group (information->contact, group);
850 }
851
852 static void
853 contact_widget_details_setup (EmpathyContactWidget *information)
854 {
855         /* FIXME: Needs new telepathy spec */
856         gtk_widget_hide (information->vbox_details);
857 }
858
859 static void
860 contact_widget_details_update (EmpathyContactWidget *information)
861 {
862         /* FIXME: Needs new telepathy spec */
863 }
864
865 static void
866 contact_widget_client_setup (EmpathyContactWidget *information)
867 {
868         /* FIXME: Needs new telepathy spec */
869         gtk_widget_hide (information->vbox_client);
870 }
871
872 static void
873 contact_widget_client_update (EmpathyContactWidget *information)
874 {
875         /* FIXME: Needs new telepathy spec */
876 }
877