1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Collabora Ltd.
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.
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.
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.
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
29 #include <glade/glade.h>
30 #include <glib/gi18n.h>
32 #include <libmissioncontrol/mc-account.h>
34 #include <libempathy/empathy-contact-manager.h>
36 #include "empathy-contact-widget.h"
37 #include "gossip-account-chooser.h"
38 #include "gossip-ui-utils.h"
41 GossipContact *contact;
44 gboolean can_change_contact;
45 GtkCellRenderer *renderer;
47 GtkWidget *vbox_contact_widget;
50 GtkWidget *vbox_contact;
51 GtkWidget *widget_avatar;
52 GtkWidget *widget_account;
54 GtkWidget *widget_alias;
55 GtkWidget *label_alias;
56 GtkWidget *entry_alias;
57 GtkWidget *hbox_presence;
58 GtkWidget *image_state;
59 GtkWidget *label_status;
60 GtkWidget *table_contact;
61 GtkWidget *hbox_contact;
64 GtkWidget *vbox_groups;
65 GtkWidget *entry_group;
66 GtkWidget *button_group;
67 GtkWidget *treeview_groups;
70 GtkWidget *vbox_details;
71 GtkWidget *table_details;
72 GtkWidget *hbox_details_requested;
75 GtkWidget *vbox_client;
76 GtkWidget *table_client;
77 GtkWidget *hbow_client_requested;
79 } EmpathyContactWidget;
82 EmpathyContactWidget *information;
85 GtkTreeIter found_iter;
88 static void contact_widget_destroy_cb (GtkWidget *widget,
89 EmpathyContactWidget *information);
90 static void contact_widget_remove_contact (EmpathyContactWidget *information);
91 static void contact_widget_set_contact (EmpathyContactWidget *information,
92 GossipContact *contact);
93 static void contact_widget_contact_setup (EmpathyContactWidget *information);
94 static void contact_widget_contact_update (EmpathyContactWidget *information);
95 static gboolean contact_widget_update_contact (EmpathyContactWidget *information);
96 static void contact_widget_account_changed_cb (GtkComboBox *widget,
97 EmpathyContactWidget *information);
98 static gboolean contact_widget_id_focus_out_cb (GtkWidget *widget,
100 EmpathyContactWidget *information);
101 static gboolean contact_widget_entry_alias_focus_event_cb (GtkEditable *editable,
102 GdkEventFocus *event,
103 EmpathyContactWidget *information);
104 static void contact_widget_name_notify_cb (EmpathyContactWidget *information);
105 static void contact_widget_presence_notify_cb (EmpathyContactWidget *information);
106 static void contact_widget_avatar_notify_cb (EmpathyContactWidget *information);
107 static void contact_widget_groups_setup (EmpathyContactWidget *information);
108 static void contact_widget_groups_update (EmpathyContactWidget *information);
109 static void contact_widget_model_setup (EmpathyContactWidget *information);
110 static void contact_widget_model_populate_columns (EmpathyContactWidget *information);
111 static void contact_widget_groups_populate_data (EmpathyContactWidget *information);
112 static void contact_widget_groups_notify_cb (EmpathyContactWidget *information);
113 static gboolean contact_widget_model_find_name (EmpathyContactWidget *information,
116 static gboolean contact_widget_model_find_name_foreach (GtkTreeModel *model,
120 static void contact_widget_cell_toggled (GtkCellRendererToggle *cell,
122 EmpathyContactWidget *information);
123 static void contact_widget_entry_group_changed_cb (GtkEditable *editable,
124 EmpathyContactWidget *information);
125 static void contact_widget_entry_group_activate_cb (GtkEntry *entry,
126 EmpathyContactWidget *information);
127 static void contact_widget_button_group_clicked_cb (GtkButton *button,
128 EmpathyContactWidget *information);
129 static void contact_widget_details_setup (EmpathyContactWidget *information);
130 static void contact_widget_details_update (EmpathyContactWidget *information);
131 static void contact_widget_client_setup (EmpathyContactWidget *information);
132 static void contact_widget_client_update (EmpathyContactWidget *information);
142 empathy_contact_widget_new (GossipContact *contact,
145 EmpathyContactWidget *information;
148 information = g_slice_new0 (EmpathyContactWidget);
149 information->editable = editable;
151 information->is_user = gossip_contact_is_user (contact);
152 information->can_change_contact = FALSE;
154 information->is_user = FALSE;
155 information->can_change_contact = TRUE;
158 glade = gossip_glade_get_file ("empathy-contact-widget.glade",
159 "vbox_contact_widget",
161 "vbox_contact_widget", &information->vbox_contact_widget,
162 "vbox_contact", &information->vbox_contact,
163 "hbox_presence", &information->hbox_presence,
164 "label_alias", &information->label_alias,
165 "image_state", &information->image_state,
166 "label_status", &information->label_status,
167 "table_contact", &information->table_contact,
168 "hbox_contact", &information->hbox_contact,
169 "vbox_groups", &information->vbox_groups,
170 "entry_group", &information->entry_group,
171 "button_group", &information->button_group,
172 "treeview_groups", &information->treeview_groups,
173 "vbox_details", &information->vbox_details,
174 "table_details", &information->table_details,
175 "hbox_details_requested", &information->hbox_details_requested,
176 "vbox_client", &information->vbox_client,
177 "table_client", &information->table_client,
178 "hbox_client_requested", &information->hbow_client_requested,
181 gossip_glade_connect (glade,
183 "vbox_contact_widget", "destroy", contact_widget_destroy_cb,
184 "entry_group", "changed", contact_widget_entry_group_changed_cb,
185 "entry_group", "activate", contact_widget_entry_group_activate_cb,
186 "button_group", "clicked", contact_widget_button_group_clicked_cb,
189 g_object_unref (glade);
191 g_object_set_data (G_OBJECT (information->vbox_contact_widget),
192 "EmpathyContactWidget",
196 contact_widget_contact_setup (information);
197 contact_widget_groups_setup (information);
198 contact_widget_details_setup (information);
199 contact_widget_client_setup (information);
201 contact_widget_set_contact (information, contact);
203 gtk_widget_show (information->vbox_contact_widget);
205 return information->vbox_contact_widget;
209 empathy_contact_widget_get_contact (GtkWidget *widget)
211 EmpathyContactWidget *information;
213 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
215 information = g_object_get_data (G_OBJECT (widget), "EmpathyContactWidget");
220 return information->contact;
224 contact_widget_destroy_cb (GtkWidget *widget,
225 EmpathyContactWidget *information)
227 contact_widget_remove_contact (information);
228 g_slice_free (EmpathyContactWidget, information);
232 contact_widget_remove_contact (EmpathyContactWidget *information)
234 if (information->contact) {
235 g_signal_handlers_disconnect_by_func (information->contact,
236 contact_widget_name_notify_cb,
238 g_signal_handlers_disconnect_by_func (information->contact,
239 contact_widget_presence_notify_cb,
241 g_signal_handlers_disconnect_by_func (information->contact,
242 contact_widget_avatar_notify_cb,
244 g_signal_handlers_disconnect_by_func (information->contact,
245 contact_widget_groups_notify_cb,
248 g_object_unref (information->contact);
249 information->contact = NULL;
254 contact_widget_set_contact (EmpathyContactWidget *information,
255 GossipContact *contact)
257 contact_widget_remove_contact (information);
259 information->contact = g_object_ref (contact);
262 /* Update information for widgets */
263 contact_widget_contact_update (information);
264 contact_widget_groups_update (information);
265 contact_widget_details_update (information);
266 contact_widget_client_update (information);
270 contact_widget_contact_setup (EmpathyContactWidget *information)
272 /* FIXME: Use GossipAvatarImage if (editable && is_user) */
273 information->widget_avatar = gtk_image_new ();
274 gtk_box_pack_end (GTK_BOX (information->hbox_contact),
275 information->widget_avatar,
279 /* Setup account label/chooser */
280 if (information->can_change_contact) {
281 information->widget_account = gossip_account_chooser_new ();
282 g_signal_connect (information->widget_account, "changed",
283 G_CALLBACK (contact_widget_account_changed_cb),
286 information->widget_account = gtk_label_new (NULL);
287 gtk_label_set_selectable (GTK_LABEL (information->widget_account), TRUE);
289 gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
290 information->widget_account,
292 gtk_widget_show (information->widget_account);
294 /* Setup id label/entry */
295 if (information->can_change_contact) {
296 information->widget_id = gtk_entry_new ();
297 g_signal_connect (information->widget_id, "focus-out-event",
298 G_CALLBACK (contact_widget_id_focus_out_cb),
301 information->widget_id = gtk_label_new (NULL);
302 gtk_label_set_selectable (GTK_LABEL (information->widget_id), TRUE);
304 gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
305 information->widget_id,
307 gtk_widget_show (information->widget_id);
309 /* Setup alias label/entry */
310 if (information->editable) {
311 information->widget_alias = gtk_entry_new ();
312 g_signal_connect (information->widget_alias, "focus-out-event",
313 G_CALLBACK (contact_widget_entry_alias_focus_event_cb),
316 information->widget_alias = gtk_label_new (NULL);
317 gtk_label_set_selectable (GTK_LABEL (information->widget_alias), TRUE);
319 gtk_table_attach_defaults (GTK_TABLE (information->table_contact),
320 information->widget_alias,
322 gtk_widget_show (information->widget_alias);
326 contact_widget_contact_update (EmpathyContactWidget *information)
328 McAccount *account = NULL;
329 const gchar *id = NULL;
331 /* Connect and get info from new contact */
332 if (information->contact) {
333 g_signal_connect_swapped (information->contact, "notify::name",
334 G_CALLBACK (contact_widget_name_notify_cb),
336 g_signal_connect_swapped (information->contact, "notify::presence",
337 G_CALLBACK (contact_widget_presence_notify_cb),
339 g_signal_connect_swapped (information->contact, "notify::avatar",
340 G_CALLBACK (contact_widget_avatar_notify_cb),
343 account = gossip_contact_get_account (information->contact);
344 id = gossip_contact_get_id (information->contact);
347 /* Update account widget */
348 if (information->can_change_contact) {
350 g_signal_handlers_block_by_func (information->widget_account,
351 contact_widget_account_changed_cb,
353 gossip_account_chooser_set_account (GOSSIP_ACCOUNT_CHOOSER (information->widget_account),
355 g_signal_handlers_unblock_by_func (information->widget_account,
356 contact_widget_account_changed_cb,
363 name = mc_account_get_display_name (account);
364 gtk_label_set_label (GTK_LABEL (information->widget_account), name);
367 /* Update id widget */
368 if (information->can_change_contact) {
369 if (!G_STR_EMPTY (id)) {
370 gtk_entry_set_text (GTK_ENTRY (information->widget_id), id);
373 gtk_label_set_label (GTK_LABEL (information->widget_id), id);
376 /* Update other widgets */
377 if (information->contact) {
378 contact_widget_name_notify_cb (information);
379 contact_widget_presence_notify_cb (information);
380 contact_widget_avatar_notify_cb (information);
382 gtk_widget_show (information->label_alias);
383 gtk_widget_show (information->widget_alias);
384 gtk_widget_show (information->hbox_presence);
386 gtk_widget_hide (information->label_alias);
387 gtk_widget_hide (information->widget_alias);
388 gtk_widget_hide (information->hbox_presence);
389 gtk_widget_hide (information->widget_avatar);
394 contact_widget_update_contact (EmpathyContactWidget *information)
399 account = gossip_account_chooser_get_account (GOSSIP_ACCOUNT_CHOOSER (information->widget_account));
400 id = gtk_entry_get_text (GTK_ENTRY (information->widget_id));
402 if (account && !G_STR_EMPTY (id)) {
403 EmpathyContactManager *manager;
404 GossipContact *contact;
406 manager = empathy_contact_manager_new ();
407 contact = empathy_contact_manager_create (manager, account, id);
408 contact_widget_set_contact (information, contact);
411 g_object_unref (contact);
413 g_object_unref (manager);
420 contact_widget_account_changed_cb (GtkComboBox *widget,
421 EmpathyContactWidget *information)
423 contact_widget_update_contact (information);
427 contact_widget_id_focus_out_cb (GtkWidget *widget,
428 GdkEventFocus *event,
429 EmpathyContactWidget *information)
431 contact_widget_update_contact (information);
436 contact_widget_entry_alias_focus_event_cb (GtkEditable *editable,
437 GdkEventFocus *event,
438 EmpathyContactWidget *information)
440 if (information->contact) {
443 name = gtk_entry_get_text (GTK_ENTRY (editable));
444 gossip_contact_set_name (information->contact, name);
451 contact_widget_name_notify_cb (EmpathyContactWidget *information)
453 if (information->editable) {
454 gtk_entry_set_text (GTK_ENTRY (information->widget_alias),
455 gossip_contact_get_name (information->contact));
457 gtk_label_set_label (GTK_LABEL (information->widget_alias),
458 gossip_contact_get_name (information->contact));
463 contact_widget_presence_notify_cb (EmpathyContactWidget *information)
465 gtk_label_set_text (GTK_LABEL (information->label_status),
466 gossip_contact_get_status (information->contact));
467 gtk_image_set_from_icon_name (GTK_IMAGE (information->image_state),
468 gossip_icon_name_for_contact (information->contact),
469 GTK_ICON_SIZE_BUTTON);
474 contact_widget_avatar_notify_cb (EmpathyContactWidget *information)
476 GdkPixbuf *avatar_pixbuf;
478 avatar_pixbuf = gossip_pixbuf_avatar_from_contact_scaled (information->contact,
482 gtk_image_set_from_pixbuf (GTK_IMAGE (information->widget_avatar),
484 gtk_widget_show (information->widget_avatar);
485 g_object_unref (avatar_pixbuf);
487 gtk_widget_hide (information->widget_avatar);
492 contact_widget_groups_setup (EmpathyContactWidget *information)
494 if (information->editable) {
495 contact_widget_model_setup (information);
500 contact_widget_groups_update (EmpathyContactWidget *information)
502 if (information->editable && information->contact) {
503 g_signal_connect_swapped (information->contact, "notify::groups",
504 G_CALLBACK (contact_widget_groups_notify_cb),
506 contact_widget_groups_populate_data (information);
508 gtk_widget_show (information->vbox_groups);
510 gtk_widget_hide (information->vbox_groups);
515 contact_widget_model_setup (EmpathyContactWidget *information)
519 GtkTreeSelection *selection;
521 view = GTK_TREE_VIEW (information->treeview_groups);
523 store = gtk_list_store_new (COL_COUNT,
524 G_TYPE_STRING, /* name */
525 G_TYPE_BOOLEAN, /* enabled */
526 G_TYPE_BOOLEAN); /* editable */
528 gtk_tree_view_set_model (view, GTK_TREE_MODEL (store));
530 selection = gtk_tree_view_get_selection (view);
531 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
533 contact_widget_model_populate_columns (information);
535 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
536 COL_NAME, GTK_SORT_ASCENDING);
538 g_object_unref (store);
542 contact_widget_model_populate_columns (EmpathyContactWidget *information)
546 GtkTreeViewColumn *column;
547 GtkCellRenderer *renderer;
550 view = GTK_TREE_VIEW (information->treeview_groups);
551 model = gtk_tree_view_get_model (view);
553 renderer = gtk_cell_renderer_toggle_new ();
554 g_signal_connect (renderer, "toggled",
555 G_CALLBACK (contact_widget_cell_toggled),
558 column = gtk_tree_view_column_new_with_attributes (_("Select"), renderer,
559 "active", COL_ENABLED,
562 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
563 gtk_tree_view_column_set_fixed_width (column, 50);
564 gtk_tree_view_append_column (view, column);
566 renderer = gtk_cell_renderer_text_new ();
567 col_offset = gtk_tree_view_insert_column_with_attributes (view,
571 /* "editable", COL_EDITABLE, */
574 g_object_set_data (G_OBJECT (renderer),
575 "column", GINT_TO_POINTER (COL_NAME));
577 column = gtk_tree_view_get_column (view, col_offset - 1);
578 gtk_tree_view_column_set_sort_column_id (column, COL_NAME);
579 gtk_tree_view_column_set_resizable (column,FALSE);
580 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
582 if (information->renderer) {
583 g_object_unref (information->renderer);
586 information->renderer = g_object_ref (renderer);
590 contact_widget_groups_populate_data (EmpathyContactWidget *information)
592 EmpathyContactManager *manager;
596 GList *my_groups, *l;
599 view = GTK_TREE_VIEW (information->treeview_groups);
600 store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
601 gtk_list_store_clear (store);
603 manager = empathy_contact_manager_new ();
604 all_groups = empathy_contact_manager_get_groups (manager);
605 my_groups = gossip_contact_get_groups (information->contact);
606 g_object_unref (manager);
608 for (l = all_groups; l; l = l->next) {
609 const gchar *group_str;
614 enabled = g_list_find_custom (my_groups,
616 (GCompareFunc) strcmp) != NULL;
618 gtk_list_store_append (store, &iter);
619 gtk_list_store_set (store, &iter,
622 COL_ENABLED, enabled,
626 g_list_free (all_groups);
630 contact_widget_groups_notify_cb (EmpathyContactWidget *information)
632 /* FIXME: not implemented */
636 contact_widget_model_find_name (EmpathyContactWidget *information,
644 if (G_STR_EMPTY (name)) {
648 data.information = information;
652 view = GTK_TREE_VIEW (information->treeview_groups);
653 model = gtk_tree_view_get_model (view);
655 gtk_tree_model_foreach (model,
656 (GtkTreeModelForeachFunc) contact_widget_model_find_name_foreach,
659 if (data.found == TRUE) {
660 *iter = data.found_iter;
668 contact_widget_model_find_name_foreach (GtkTreeModel *model,
675 gtk_tree_model_get (model, iter,
683 if (data->name && strcmp (data->name, name) == 0) {
685 data->found_iter = *iter;
698 contact_widget_cell_toggled (GtkCellRendererToggle *cell,
700 EmpathyContactWidget *information)
710 view = GTK_TREE_VIEW (information->treeview_groups);
711 model = gtk_tree_view_get_model (view);
712 store = GTK_LIST_STORE (model);
714 path = gtk_tree_path_new_from_string (path_string);
716 gtk_tree_model_get_iter (model, &iter, path);
717 gtk_tree_model_get (model, &iter,
718 COL_ENABLED, &enabled,
722 gtk_list_store_set (store, &iter, COL_ENABLED, !enabled, -1);
723 gtk_tree_path_free (path);
727 gossip_contact_remove_group (information->contact, group);
729 gossip_contact_add_group (information->contact, group);
737 contact_widget_entry_group_changed_cb (GtkEditable *editable,
738 EmpathyContactWidget *information)
743 group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
745 if (contact_widget_model_find_name (information, group, &iter)) {
746 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group), FALSE);
749 gtk_widget_set_sensitive (GTK_WIDGET (information->button_group),
750 !G_STR_EMPTY (group));
755 contact_widget_entry_group_activate_cb (GtkEntry *entry,
756 EmpathyContactWidget *information)
758 gtk_widget_activate (GTK_WIDGET (information->button_group));
762 contact_widget_button_group_clicked_cb (GtkButton *button,
763 EmpathyContactWidget *information)
770 view = GTK_TREE_VIEW (information->treeview_groups);
771 store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
773 group = gtk_entry_get_text (GTK_ENTRY (information->entry_group));
775 gtk_list_store_append (store, &iter);
776 gtk_list_store_set (store, &iter,
781 gossip_contact_add_group (information->contact, group);
785 contact_widget_details_setup (EmpathyContactWidget *information)
787 /* FIXME: Needs new telepathy spec */
788 gtk_widget_hide (information->vbox_details);
792 contact_widget_details_update (EmpathyContactWidget *information)
794 /* FIXME: Needs new telepathy spec */
798 contact_widget_client_setup (EmpathyContactWidget *information)
800 /* FIXME: Needs new telepathy spec */
801 gtk_widget_hide (information->vbox_client);
805 contact_widget_client_update (EmpathyContactWidget *information)
807 /* FIXME: Needs new telepathy spec */