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