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