]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-widget.c
Removed some tasks from TODO
[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-2008 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::presence-message",
433                                           G_CALLBACK (contact_widget_presence_notify_cb),
434                                           information);
435                 g_signal_connect_swapped (information->contact, "notify::avatar",
436                                           G_CALLBACK (contact_widget_avatar_notify_cb),
437                                           information);
438
439                 account = empathy_contact_get_account (information->contact);
440                 id = empathy_contact_get_id (information->contact);
441         }
442
443         /* Update account widget */
444         if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ACCOUNT) {
445                 if (account) {
446                         g_signal_handlers_block_by_func (information->widget_account,
447                                                          contact_widget_account_changed_cb,
448                                                          information);
449                         empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (information->widget_account),
450                                                             account);
451                         g_signal_handlers_unblock_by_func (information->widget_account,
452                                                            contact_widget_account_changed_cb,
453                                                            information);
454                 }
455         } else {
456                 if (account) {
457                         const gchar *name;
458
459                         name = mc_account_get_display_name (account);
460                         gtk_label_set_label (GTK_LABEL (information->widget_account), name);
461                 }
462         }
463
464         /* Update id widget */
465         if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) {
466                 gtk_entry_set_text (GTK_ENTRY (information->widget_id), id ? id : "");
467         } else {
468                 gtk_label_set_label (GTK_LABEL (information->widget_id), id ? id : "");
469         }
470         /* Update other widgets */
471         if (information->contact) {
472                 contact_widget_name_notify_cb (information);
473                 contact_widget_presence_notify_cb (information);
474                 contact_widget_avatar_notify_cb (information);
475
476                 gtk_widget_show (information->label_alias);
477                 gtk_widget_show (information->widget_alias);
478                 gtk_widget_show (information->hbox_presence);
479                 gtk_widget_show (information->widget_avatar);
480         } else {
481                 gtk_widget_hide (information->label_alias);
482                 gtk_widget_hide (information->widget_alias);
483                 gtk_widget_hide (information->hbox_presence);
484                 gtk_widget_hide (information->widget_avatar);
485         }
486 }
487
488 static void
489 contact_widget_change_contact (EmpathyContactWidget *information)
490 {
491         EmpathyContact *contact;
492         McAccount      *account;
493
494         account = empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (information->widget_account));
495         if (!account) {
496                 return;
497         }
498
499         if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_ID) {
500                 const gchar *id;
501
502                 id = gtk_entry_get_text (GTK_ENTRY (information->widget_id));
503                 if (G_STR_EMPTY (id)) {
504                         return;
505                 }
506
507                 contact = empathy_contact_factory_get_from_id (information->factory,
508                                                                account, id);
509         } else {
510                 contact = empathy_contact_factory_get_user (information->factory,
511                                                             account);
512         }
513
514         if (contact) {
515                 contact_widget_set_contact (information, contact);
516                 g_object_unref (contact);
517         }
518 }
519
520 static void
521 contact_widget_avatar_changed_cb (EmpathyAvatarChooser *chooser,
522                                   EmpathyContactWidget *information)
523 {
524         if (information->contact &&
525             empathy_contact_is_user (information->contact)) {
526                 McAccount   *account;
527                 const gchar *data;
528                 gsize        size;
529                 const gchar *mime_type;
530
531                 account = empathy_contact_get_account (information->contact);
532                 empathy_avatar_chooser_get_image_data (EMPATHY_AVATAR_CHOOSER (information->widget_avatar),
533                                                        &data, &size, &mime_type);
534                 empathy_contact_factory_set_avatar (information->factory,
535                                                     account,
536                                                     data, size, mime_type);
537         }
538 }
539
540 static void
541 contact_widget_account_changed_cb (GtkComboBox          *widget,
542                                    EmpathyContactWidget *information)
543 {
544         contact_widget_change_contact (information);
545 }
546
547 static gboolean
548 contact_widget_id_focus_out_cb (GtkWidget            *widget,
549                                 GdkEventFocus        *event,
550                                 EmpathyContactWidget *information)
551 {
552         contact_widget_change_contact (information);
553         return FALSE;
554 }
555
556 static gboolean
557 contact_widget_entry_alias_focus_event_cb (GtkEditable          *editable,
558                                            GdkEventFocus        *event,
559                                            EmpathyContactWidget *information)
560 {
561         if (information->contact) {
562                 const gchar *alias;
563
564                 alias = gtk_entry_get_text (GTK_ENTRY (editable));
565                 empathy_contact_factory_set_alias (information->factory,
566                                                   information->contact,
567                                                   alias);
568         }
569
570         return FALSE;
571 }
572
573 static void
574 contact_widget_name_notify_cb (EmpathyContactWidget *information)
575 {
576         if (GTK_IS_ENTRY (information->widget_alias)) {
577                 gtk_entry_set_text (GTK_ENTRY (information->widget_alias),
578                                     empathy_contact_get_name (information->contact));
579         } else {
580                 gtk_label_set_label (GTK_LABEL (information->widget_alias),
581                                      empathy_contact_get_name (information->contact));
582         }
583 }
584
585 static void
586 contact_widget_presence_notify_cb (EmpathyContactWidget *information)
587 {
588         gtk_label_set_text (GTK_LABEL (information->label_status),
589                             empathy_contact_get_status (information->contact));
590         gtk_image_set_from_icon_name (GTK_IMAGE (information->image_state),
591                                       empathy_icon_name_for_contact (information->contact),
592                                       GTK_ICON_SIZE_BUTTON);
593
594 }
595
596 static void
597 contact_widget_avatar_notify_cb (EmpathyContactWidget *information)
598 {
599         EmpathyAvatar *avatar = NULL;
600
601         if (information->contact) {
602                 avatar = empathy_contact_get_avatar (information->contact);
603         }
604         if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_AVATAR) {
605                 g_signal_handlers_block_by_func (information->widget_avatar,
606                                                  contact_widget_avatar_changed_cb,
607                                                  information);
608                 empathy_avatar_chooser_set (EMPATHY_AVATAR_CHOOSER (information->widget_avatar),
609                                             avatar);
610                 g_signal_handlers_unblock_by_func (information->widget_avatar,
611                                                    contact_widget_avatar_changed_cb,
612                                                    information);
613         } else {
614                 empathy_avatar_image_set (EMPATHY_AVATAR_IMAGE (information->widget_avatar),
615                                           avatar);
616         }
617 }
618
619 static void
620 contact_widget_groups_setup (EmpathyContactWidget *information)
621 {
622         if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_GROUPS) {
623                 information->manager = empathy_contact_manager_new ();
624                 contact_widget_model_setup (information);
625         }
626 }
627
628 static void
629 contact_widget_groups_update (EmpathyContactWidget *information)
630 {
631         if (information->flags & EMPATHY_CONTACT_WIDGET_EDIT_GROUPS &&
632             information->contact) {
633                 g_signal_connect_swapped (information->contact, "notify::groups",
634                                           G_CALLBACK (contact_widget_groups_notify_cb),
635                                           information);
636                 contact_widget_groups_populate_data (information);
637
638                 gtk_widget_show (information->vbox_groups);
639         } else {
640                 gtk_widget_hide (information->vbox_groups);
641         }
642 }
643
644 static void
645 contact_widget_model_setup (EmpathyContactWidget *information)
646 {
647         GtkTreeView      *view;
648         GtkListStore     *store;
649         GtkTreeSelection *selection;
650
651         view = GTK_TREE_VIEW (information->treeview_groups);
652
653         store = gtk_list_store_new (COL_COUNT,
654                                     G_TYPE_STRING,   /* name */
655                                     G_TYPE_BOOLEAN,  /* enabled */
656                                     G_TYPE_BOOLEAN); /* editable */
657
658         gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
659
660         selection = gtk_tree_view_get_selection (view);
661         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
662
663         contact_widget_model_populate_columns (information);
664
665         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
666                                               COL_NAME, GTK_SORT_ASCENDING);
667
668         g_object_unref (store);
669 }
670
671 static void
672 contact_widget_model_populate_columns (EmpathyContactWidget *information)
673 {
674         GtkTreeView       *view;
675         GtkTreeModel      *model;
676         GtkTreeViewColumn *column;
677         GtkCellRenderer   *renderer;
678         guint              col_offset;
679
680         view = GTK_TREE_VIEW (information->treeview_groups);
681         model = gtk_tree_view_get_model (view);
682
683         renderer = gtk_cell_renderer_toggle_new ();
684         g_signal_connect (renderer, "toggled",
685                           G_CALLBACK (contact_widget_cell_toggled),
686                           information);
687
688         column = gtk_tree_view_column_new_with_attributes (_("Select"), renderer,
689                                                            "active", COL_ENABLED,
690                                                            NULL);
691
692         gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
693         gtk_tree_view_column_set_fixed_width (column, 50);
694         gtk_tree_view_append_column (view, column);
695
696         renderer = gtk_cell_renderer_text_new ();
697         col_offset = gtk_tree_view_insert_column_with_attributes (view,
698                                                                   -1, _("Group"),
699                                                                   renderer,
700                                                                   "text", COL_NAME,
701                                                                   /* "editable", COL_EDITABLE, */
702                                                                   NULL);
703
704         g_object_set_data (G_OBJECT (renderer),
705                            "column", GINT_TO_POINTER (COL_NAME));
706
707         column = gtk_tree_view_get_column (view, col_offset - 1);
708         gtk_tree_view_column_set_sort_column_id (column, COL_NAME);
709         gtk_tree_view_column_set_resizable (column,FALSE);
710         gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
711
712         if (information->renderer) {
713                 g_object_unref (information->renderer);
714         }
715
716         information->renderer = g_object_ref (renderer);
717 }
718
719 static void
720 contact_widget_groups_populate_data (EmpathyContactWidget *information)
721 {
722         GtkTreeView  *view;
723         GtkListStore *store;
724         GtkTreeIter   iter;
725         GList        *my_groups, *l;
726         GList        *all_groups;
727
728         view = GTK_TREE_VIEW (information->treeview_groups);
729         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
730         gtk_list_store_clear (store);
731
732         all_groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (information->manager));
733         my_groups = empathy_contact_list_get_groups (EMPATHY_CONTACT_LIST (information->manager),
734                                                      information->contact);
735
736         for (l = all_groups; l; l = l->next) {
737                 const gchar *group_str;
738                 gboolean     enabled;
739
740                 group_str = l->data;
741
742                 enabled = g_list_find_custom (my_groups,
743                                               group_str,
744                                               (GCompareFunc) strcmp) != NULL;
745
746                 gtk_list_store_append (store, &iter);
747                 gtk_list_store_set (store, &iter,
748                                     COL_NAME, group_str,
749                                     COL_EDITABLE, TRUE,
750                                     COL_ENABLED, enabled,
751                                     -1);
752         }
753
754         g_list_foreach (all_groups, (GFunc) g_free, NULL);
755         g_list_foreach (my_groups, (GFunc) g_free, NULL);
756         g_list_free (all_groups);
757         g_list_free (my_groups);
758 }
759
760 static void
761 contact_widget_groups_notify_cb (EmpathyContactWidget *information)
762 {
763         /* FIXME: not implemented */
764 }
765
766 static gboolean
767 contact_widget_model_find_name (EmpathyContactWidget *information,
768                                 const gchar          *name,
769                                 GtkTreeIter          *iter)
770 {
771         GtkTreeView  *view;
772         GtkTreeModel *model;
773         FindName      data;
774
775         if (G_STR_EMPTY (name)) {
776                 return FALSE;
777         }
778
779         data.information = information;
780         data.name = name;
781         data.found = FALSE;
782
783         view = GTK_TREE_VIEW (information->treeview_groups);
784         model = gtk_tree_view_get_model (view);
785
786         gtk_tree_model_foreach (model,
787                                 (GtkTreeModelForeachFunc) contact_widget_model_find_name_foreach,
788                                 &data);
789
790         if (data.found == TRUE) {
791                 *iter = data.found_iter;
792                 return TRUE;
793         }
794
795         return FALSE;
796 }
797
798 static gboolean
799 contact_widget_model_find_name_foreach (GtkTreeModel *model,
800                                         GtkTreePath  *path,
801                                         GtkTreeIter  *iter,
802                                         FindName     *data)
803 {
804         gchar *name;
805
806         gtk_tree_model_get (model, iter,
807                             COL_NAME, &name,
808                             -1);
809
810         if (!name) {
811                 return FALSE;
812         }
813
814         if (data->name && strcmp (data->name, name) == 0) {
815                 data->found = TRUE;
816                 data->found_iter = *iter;
817
818                 g_free (name);
819
820                 return TRUE;
821         }
822
823         g_free (name);
824
825         return FALSE;
826 }
827
828 static void
829 contact_widget_cell_toggled (GtkCellRendererToggle *cell,
830                              gchar                 *path_string,
831                              EmpathyContactWidget  *information)
832 {
833         GtkTreeView  *view;
834         GtkTreeModel *model;
835         GtkListStore *store;
836         GtkTreePath  *path;
837         GtkTreeIter   iter;
838         gboolean      enabled;
839         gchar        *group;
840
841         view = GTK_TREE_VIEW (information->treeview_groups);
842         model = gtk_tree_view_get_model (view);
843         store = GTK_LIST_STORE (model);
844
845         path = gtk_tree_path_new_from_string (path_string);
846
847         gtk_tree_model_get_iter (model, &iter, path);
848         gtk_tree_model_get (model, &iter,
849                             COL_ENABLED, &enabled,
850                             COL_NAME, &group,
851                             -1);
852
853         gtk_list_store_set (store, &iter, COL_ENABLED, !enabled, -1);
854         gtk_tree_path_free (path);
855
856         if (group) {
857                 if (enabled) {
858                         empathy_contact_list_remove_from_group (EMPATHY_CONTACT_LIST (information->manager),
859                                                                 information->contact,
860                                                                 group);
861                 } else {
862                         empathy_contact_list_add_to_group (EMPATHY_CONTACT_LIST (information->manager),
863                                                            information->contact,
864                                                            group);
865                 }
866
867                 g_free (group);
868         }
869 }
870
871 static void
872 contact_widget_entry_group_changed_cb (GtkEditable           *editable,
873                                        EmpathyContactWidget  *information)
874 {
875         GtkTreeIter  iter;
876         const gchar *group;
877
878         group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
879
880         if (contact_widget_model_find_name (information, group, &iter)) {
881                 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group), FALSE);
882
883         } else {
884                 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group),
885                                           !G_STR_EMPTY (group));
886         }
887 }
888
889 static void
890 contact_widget_entry_group_activate_cb (GtkEntry              *entry,
891                                         EmpathyContactWidget  *information)
892 {
893         gtk_widget_activate (GTK_WIDGET (information->button_group));
894 }
895
896 static void
897 contact_widget_button_group_clicked_cb (GtkButton             *button,
898                                         EmpathyContactWidget  *information)
899 {
900         GtkTreeView  *view;
901         GtkListStore *store;
902         GtkTreeIter   iter;
903         const gchar  *group;
904
905         view = GTK_TREE_VIEW (information->treeview_groups);
906         store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
907
908         group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
909
910         gtk_list_store_append (store, &iter);
911         gtk_list_store_set (store, &iter,
912                             COL_NAME, group,
913                             COL_ENABLED, TRUE,
914                             -1);
915
916         empathy_contact_list_add_to_group (EMPATHY_CONTACT_LIST (information->manager),
917                                            information->contact,
918                                            group);
919 }
920
921 static void
922 contact_widget_details_setup (EmpathyContactWidget *information)
923 {
924         /* FIXME: Needs new telepathy spec */
925         gtk_widget_hide (information->vbox_details);
926 }
927
928 static void
929 contact_widget_details_update (EmpathyContactWidget *information)
930 {
931         /* FIXME: Needs new telepathy spec */
932 }
933
934 static void
935 contact_widget_client_setup (EmpathyContactWidget *information)
936 {
937         /* FIXME: Needs new telepathy spec */
938         gtk_widget_hide (information->vbox_client);
939 }
940
941 static void
942 contact_widget_client_update (EmpathyContactWidget *information)
943 {
944         /* FIXME: Needs new telepathy spec */
945 }
946