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