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