]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-list-view.c
Request media channel when clicking on call icon.
[empathy.git] / libempathy-gtk / empathy-contact-list-view.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2005-2007 Imendio AB
4  * Copyright (C) 2007 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Authors: Mikael Hallendal <micke@imendio.com>
22  *          Martyn Russell <martyn@imendio.com>
23  *          Xavier Claessens <xclaesse@gmail.com>
24  */
25
26 #include "config.h"
27
28 #include <string.h>
29
30 #include <glib/gi18n.h>
31 #include <gtk/gtk.h>
32 #include <glade/glade.h>
33
34 #include <libmissioncontrol/mc-account.h>
35 #include <libmissioncontrol/mission-control.h>
36
37 #include <libempathy/empathy-contact-factory.h>
38 #include <libempathy/empathy-contact-list.h>
39 #include <libempathy/empathy-log-manager.h>
40 #include <libempathy/empathy-debug.h>
41 #include <libempathy/empathy-utils.h>
42 #include <libempathy/empathy-marshal.h>
43
44 #include "empathy-contact-list-view.h"
45 #include "empathy-contact-list-store.h"
46 #include "empathy-images.h"
47 #include "empathy-contact-groups.h"
48 #include "empathy-cell-renderer-expander.h"
49 #include "empathy-cell-renderer-text.h"
50 #include "empathy-cell-renderer-activatable.h"
51 #include "empathy-ui-utils.h"
52 #include "empathy-contact-dialogs.h"
53 //#include "empathy-chat-invite.h"
54 //#include "empathy-ft-window.h"
55 #include "empathy-log-window.h"
56
57 #define DEBUG_DOMAIN "ContactListView"
58
59 /* Flashing delay for icons (milliseconds). */
60 #define FLASH_TIMEOUT 500
61
62 /* Active users are those which have recently changed state
63  * (e.g. online, offline or from normal to a busy state).
64  */
65
66 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT_LIST_VIEW, EmpathyContactListViewPriv))
67
68 struct _EmpathyContactListViewPriv {
69         EmpathyContactListStore *store;
70         GtkUIManager            *ui;
71         GtkTreeRowReference     *drag_row;
72 };
73
74 typedef struct {
75         EmpathyContactListView *view;
76         GtkTreePath           *path;
77         guint                  timeout_id;
78 } DragMotionData;
79
80 typedef struct {
81         EmpathyContactListView *view;
82         EmpathyContact         *contact;
83         gboolean               remove;
84 } ShowActiveData;
85
86 static void        empathy_contact_list_view_class_init         (EmpathyContactListViewClass *klass);
87 static void        empathy_contact_list_view_init               (EmpathyContactListView      *list);
88 static void        contact_list_view_finalize                  (GObject                    *object);
89 static void        contact_list_view_get_property              (GObject                    *object,
90                                                                 guint                       param_id,
91                                                                 GValue                     *value,
92                                                                 GParamSpec                 *pspec);
93 static void        contact_list_view_set_property              (GObject                    *object,
94                                                                 guint                       param_id,
95                                                                 const GValue               *value,
96                                                                 GParamSpec                 *pspec);
97 static void        contact_list_view_setup                     (EmpathyContactListView      *view);
98 static void        contact_list_view_row_has_child_toggled_cb  (GtkTreeModel               *model,
99                                                                 GtkTreePath                *path,
100                                                                 GtkTreeIter                *iter,
101                                                                 EmpathyContactListView      *view);
102 static void        contact_list_view_drag_data_received        (GtkWidget                  *widget,
103                                                                 GdkDragContext             *context,
104                                                                 gint                        x,
105                                                                 gint                        y,
106                                                                 GtkSelectionData           *selection,
107                                                                 guint                       info,
108                                                                 guint                       time);
109 static gboolean    contact_list_view_drag_motion               (GtkWidget                  *widget,
110                                                                 GdkDragContext             *context,
111                                                                 gint                        x,
112                                                                 gint                        y,
113                                                                 guint                       time);
114 static gboolean    contact_list_view_drag_motion_cb            (DragMotionData             *data);
115 static void        contact_list_view_drag_begin                (GtkWidget                  *widget,
116                                                                 GdkDragContext             *context);
117 static void        contact_list_view_drag_data_get             (GtkWidget                  *widget,
118                                                                 GdkDragContext             *context,
119                                                                 GtkSelectionData           *selection,
120                                                                 guint                       info,
121                                                                 guint                       time);
122 static void        contact_list_view_drag_end                  (GtkWidget                  *widget,
123                                                                 GdkDragContext             *context);
124 static gboolean    contact_list_view_drag_drop                 (GtkWidget                  *widget,
125                                                                 GdkDragContext             *drag_context,
126                                                                 gint                        x,
127                                                                 gint                        y,
128                                                                 guint                       time);
129 static void        contact_list_view_cell_set_background       (EmpathyContactListView      *view,
130                                                                 GtkCellRenderer            *cell,
131                                                                 gboolean                    is_group,
132                                                                 gboolean                    is_active);
133 static void        contact_list_view_pixbuf_cell_data_func     (GtkTreeViewColumn          *tree_column,
134                                                                 GtkCellRenderer            *cell,
135                                                                 GtkTreeModel               *model,
136                                                                 GtkTreeIter                *iter,
137                                                                 EmpathyContactListView     *view);
138 static void        contact_list_view_voip_cell_data_func       (GtkTreeViewColumn          *tree_column,
139                                                                 GtkCellRenderer            *cell,
140                                                                 GtkTreeModel               *model,
141                                                                 GtkTreeIter                *iter,
142                                                                 EmpathyContactListView     *view);
143 static void        contact_list_view_avatar_cell_data_func     (GtkTreeViewColumn          *tree_column,
144                                                                 GtkCellRenderer            *cell,
145                                                                 GtkTreeModel               *model,
146                                                                 GtkTreeIter                *iter,
147                                                                 EmpathyContactListView      *view);
148 static void        contact_list_view_text_cell_data_func       (GtkTreeViewColumn          *tree_column,
149                                                                 GtkCellRenderer            *cell,
150                                                                 GtkTreeModel               *model,
151                                                                 GtkTreeIter                *iter,
152                                                                 EmpathyContactListView      *view);
153 static void        contact_list_view_expander_cell_data_func   (GtkTreeViewColumn          *column,
154                                                                 GtkCellRenderer            *cell,
155                                                                 GtkTreeModel               *model,
156                                                                 GtkTreeIter                *iter,
157                                                                 EmpathyContactListView      *view);
158 static GtkWidget * contact_list_view_get_contact_menu          (EmpathyContactListView      *view,
159                                                                 gboolean                    can_send_file,
160                                                                 gboolean                    can_show_log,
161                                                                 gboolean                    can_voip);
162 static gboolean    contact_list_view_button_press_event_cb     (EmpathyContactListView      *view,
163                                                                 GdkEventButton             *event,
164                                                                 gpointer                    user_data);
165 static void        contact_list_view_row_activated_cb          (EmpathyContactListView      *view,
166                                                                 GtkTreePath                *path,
167                                                                 GtkTreeViewColumn          *col,
168                                                                 gpointer                    user_data);
169 static void        contact_list_view_voip_activated_cb         (EmpathyCellRendererActivatable *cell,
170                                                                 const gchar                *path_string,
171                                                                 EmpathyContactListView     *view);
172 static void        contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView      *view,
173                                                                 GtkTreeIter                *iter,
174                                                                 GtkTreePath                *path,
175                                                                 gpointer                    user_data);
176 static void        contact_list_view_action_cb                 (GtkAction                  *action,
177                                                                 EmpathyContactListView      *view);
178 static void        contact_list_view_action_activated          (EmpathyContactListView      *view,
179                                                                 EmpathyContact              *contact);
180 static void        contact_list_view_voip_activated            (EmpathyContactListView      *view,
181                                                                 EmpathyContact              *contact);
182
183 enum {
184         PROP_0,
185 };
186
187 static const GtkActionEntry entries[] = {
188         { "ContactMenu", NULL,
189           N_("_Contact"), NULL, NULL,
190           NULL
191         },
192         { "GroupMenu", NULL,
193           N_("_Group"),NULL, NULL,
194           NULL
195         },
196         { "Chat", EMPATHY_IMAGE_MESSAGE,
197           N_("_Chat"), NULL, N_("Chat with contact"),
198           G_CALLBACK (contact_list_view_action_cb)
199         },
200         { "Information", EMPATHY_IMAGE_CONTACT_INFORMATION,
201           N_("Infor_mation"), "<control>I", N_("View contact information"),
202           G_CALLBACK (contact_list_view_action_cb)
203         },
204         { "Rename", NULL,
205           N_("Re_name"), NULL, N_("Rename"),
206           G_CALLBACK (contact_list_view_action_cb)
207         },
208         { "Edit", GTK_STOCK_EDIT,
209           N_("_Edit"), NULL, N_("Edit the groups and name for this contact"),
210           G_CALLBACK (contact_list_view_action_cb)
211         },
212         { "Remove", GTK_STOCK_REMOVE,
213           N_("_Remove"), NULL, N_("Remove contact"),
214           G_CALLBACK (contact_list_view_action_cb)
215         },
216         { "Invite", EMPATHY_IMAGE_GROUP_MESSAGE,
217           N_("_Invite to Chat Room"), NULL, N_("Invite to a currently open chat room"),
218           G_CALLBACK (contact_list_view_action_cb)
219         },
220         { "SendFile", NULL,
221           N_("_Send File..."), NULL, N_("Send a file"),
222           G_CALLBACK (contact_list_view_action_cb)
223         },
224         { "Log", GTK_STOCK_JUSTIFY_LEFT,
225           N_("_View Previous Conversations"), NULL, N_("View previous conversations with this contact"),
226           G_CALLBACK (contact_list_view_action_cb)
227         },
228         { "Call", EMPATHY_IMAGE_VOIP,
229           N_("_Call"), NULL, N_("Start a voice or video conversation with this contact"),
230           G_CALLBACK (contact_list_view_action_cb)
231         },
232 };
233
234 static guint n_entries = G_N_ELEMENTS (entries);
235
236 static const gchar *ui_info =
237         "<ui>"
238         "  <popup name='Contact'>"
239         "    <menuitem action='Chat'/>"
240         "    <menuitem action='Call'/>"
241         "    <menuitem action='Log'/>"
242         "    <menuitem action='SendFile'/>"
243         "    <separator/>"
244         "    <menuitem action='Invite'/>"
245         "    <separator/>"
246         "    <menuitem action='Edit'/>"
247         "    <menuitem action='Remove'/>"
248         "    <separator/>"
249         "    <menuitem action='Information'/>"
250         "  </popup>"
251         "  <popup name='Group'>"
252         "    <menuitem action='Rename'/>"
253         "  </popup>"
254         "</ui>";
255
256 enum DndDragType {
257         DND_DRAG_TYPE_CONTACT_ID,
258         DND_DRAG_TYPE_URL,
259         DND_DRAG_TYPE_STRING,
260 };
261
262 static const GtkTargetEntry drag_types_dest[] = {
263         { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
264         { "text/uri-list",   0, DND_DRAG_TYPE_URL },
265         { "text/plain",      0, DND_DRAG_TYPE_STRING },
266         { "STRING",          0, DND_DRAG_TYPE_STRING },
267 };
268
269 static const GtkTargetEntry drag_types_source[] = {
270         { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID },
271 };
272
273 static GdkAtom drag_atoms_dest[G_N_ELEMENTS (drag_types_dest)];
274 static GdkAtom drag_atoms_source[G_N_ELEMENTS (drag_types_source)];
275
276 enum {
277         DRAG_CONTACT_RECEIVED,
278         LAST_SIGNAL
279 };
280
281 static guint signals[LAST_SIGNAL];
282
283 G_DEFINE_TYPE (EmpathyContactListView, empathy_contact_list_view, GTK_TYPE_TREE_VIEW);
284
285 static void
286 empathy_contact_list_view_class_init (EmpathyContactListViewClass *klass)
287 {
288         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
289         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
290
291         object_class->finalize = contact_list_view_finalize;
292         object_class->get_property = contact_list_view_get_property;
293         object_class->set_property = contact_list_view_set_property;
294
295         widget_class->drag_data_received = contact_list_view_drag_data_received;
296         widget_class->drag_drop          = contact_list_view_drag_drop;
297         widget_class->drag_begin         = contact_list_view_drag_begin;
298         widget_class->drag_data_get      = contact_list_view_drag_data_get;
299         widget_class->drag_end           = contact_list_view_drag_end;
300         /* FIXME: noticed but when you drag the row over the treeview
301          * fast, it seems to stop redrawing itself, if we don't
302          * connect this signal, all is fine.
303          */
304         widget_class->drag_motion        = contact_list_view_drag_motion;
305
306         signals[DRAG_CONTACT_RECEIVED] =
307                 g_signal_new ("drag-contact-received",
308                               G_OBJECT_CLASS_TYPE (klass),
309                               G_SIGNAL_RUN_LAST,
310                               0,
311                               NULL, NULL,
312                               empathy_marshal_VOID__OBJECT_STRING_STRING,
313                               G_TYPE_NONE,
314                               3, EMPATHY_TYPE_CONTACT, G_TYPE_STRING, G_TYPE_STRING);
315
316         g_type_class_add_private (object_class, sizeof (EmpathyContactListViewPriv));
317 }
318
319 static void
320 empathy_contact_list_view_init (EmpathyContactListView *view)
321 {
322         EmpathyContactListViewPriv *priv;
323         GtkActionGroup            *action_group;
324         GError                    *error = NULL;
325
326         priv = GET_PRIV (view);
327
328         /* Get saved group states. */
329         empathy_contact_groups_get_all ();
330
331         /* Set up UI Manager */
332         priv->ui = gtk_ui_manager_new ();
333
334         action_group = gtk_action_group_new ("Actions");
335         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
336         gtk_action_group_add_actions (action_group, entries, n_entries, view);
337         gtk_ui_manager_insert_action_group (priv->ui, action_group, 0);
338
339         if (!gtk_ui_manager_add_ui_from_string (priv->ui, ui_info, -1, &error)) {
340                 g_warning ("Could not build contact menus from string:'%s'", error->message);
341                 g_error_free (error);
342         }
343
344         g_object_unref (action_group);
345
346         gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (view), 
347                                               empathy_contact_list_store_row_separator_func,
348                                               NULL, NULL);
349
350         /* Connect to tree view signals rather than override. */
351         g_signal_connect (view,
352                           "button-press-event",
353                           G_CALLBACK (contact_list_view_button_press_event_cb),
354                           NULL);
355         g_signal_connect (view,
356                           "row-activated",
357                           G_CALLBACK (contact_list_view_row_activated_cb),
358                           NULL);
359         g_signal_connect (view,
360                           "row-expanded",
361                           G_CALLBACK (contact_list_view_row_expand_or_collapse_cb),
362                           GINT_TO_POINTER (TRUE));
363         g_signal_connect (view,
364                           "row-collapsed",
365                           G_CALLBACK (contact_list_view_row_expand_or_collapse_cb),
366                           GINT_TO_POINTER (FALSE));
367 }
368
369 static void
370 contact_list_view_finalize (GObject *object)
371 {
372         EmpathyContactListViewPriv *priv;
373
374         priv = GET_PRIV (object);
375
376         if (priv->ui) {
377                 g_object_unref (priv->ui);
378         }
379         if (priv->store) {
380                 g_object_unref (priv->store);
381         }
382
383         G_OBJECT_CLASS (empathy_contact_list_view_parent_class)->finalize (object);
384 }
385
386 static void
387 contact_list_view_get_property (GObject    *object,
388                                 guint       param_id,
389                                 GValue     *value,
390                                 GParamSpec *pspec)
391 {
392         EmpathyContactListViewPriv *priv;
393
394         priv = GET_PRIV (object);
395
396         switch (param_id) {
397         default:
398                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
399                 break;
400         };
401 }
402
403 static void
404 contact_list_view_set_property (GObject      *object,
405                                 guint         param_id,
406                                 const GValue *value,
407                                 GParamSpec   *pspec)
408 {
409         EmpathyContactListViewPriv *priv;
410
411         priv = GET_PRIV (object);
412
413         switch (param_id) {
414         default:
415                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
416                 break;
417         };
418 }
419
420 EmpathyContactListView *
421 empathy_contact_list_view_new (EmpathyContactListStore *store)
422 {
423         EmpathyContactListViewPriv *priv;
424         EmpathyContactListView     *view;
425         
426         view = g_object_new (EMPATHY_TYPE_CONTACT_LIST_VIEW, NULL);
427         priv = GET_PRIV (view);
428
429         priv->store = g_object_ref (store);
430         contact_list_view_setup (view);
431
432         return view;
433 }
434
435 EmpathyContact *
436 empathy_contact_list_view_get_selected (EmpathyContactListView *view)
437 {
438         EmpathyContactListViewPriv *priv;
439         GtkTreeSelection          *selection;
440         GtkTreeIter                iter;
441         GtkTreeModel              *model;
442         EmpathyContact             *contact;
443
444         g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL);
445
446         priv = GET_PRIV (view);
447
448         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
449         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
450                 return NULL;
451         }
452
453         gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1);
454
455         return contact;
456 }
457
458 gchar *
459 empathy_contact_list_view_get_selected_group (EmpathyContactListView *view)
460 {
461         EmpathyContactListViewPriv *priv;
462         GtkTreeSelection          *selection;
463         GtkTreeIter                iter;
464         GtkTreeModel              *model;
465         gboolean                   is_group;
466         gchar                     *name;
467
468         g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL);
469
470         priv = GET_PRIV (view);
471
472         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
473         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
474                 return NULL;
475         }
476
477         gtk_tree_model_get (model, &iter,
478                             COL_IS_GROUP, &is_group,
479                             COL_NAME, &name,
480                             -1);
481
482         if (!is_group) {
483                 g_free (name);
484                 return NULL;
485         }
486
487         return name;
488 }
489
490 GtkWidget *
491 empathy_contact_list_view_get_group_menu (EmpathyContactListView *view)
492 {
493         EmpathyContactListViewPriv *priv;
494         GtkWidget                 *widget;
495
496         g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL);
497
498         priv = GET_PRIV (view);
499
500         widget = gtk_ui_manager_get_widget (priv->ui, "/Group");
501
502         return widget;
503 }
504
505 GtkWidget *
506 empathy_contact_list_view_get_contact_menu (EmpathyContactListView *view,
507                                             EmpathyContact         *contact)
508 {
509         EmpathyLogManager *log_manager;
510         gboolean           can_show_log;
511         gboolean           can_send_file;
512         gboolean           can_voip;
513
514         g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view), NULL);
515         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
516
517         log_manager = empathy_log_manager_new ();
518         can_show_log = empathy_log_manager_exists (log_manager,
519                                                    empathy_contact_get_account (contact),
520                                                    empathy_contact_get_id (contact),
521                                                    FALSE);
522         g_object_unref (log_manager);
523         can_send_file = FALSE;
524         can_voip = empathy_contact_can_voip (contact);
525
526         return contact_list_view_get_contact_menu (view,
527                                                    can_send_file,
528                                                    can_show_log,
529                                                    can_voip);
530 }
531
532 static void
533 contact_list_view_setup (EmpathyContactListView *view)
534 {
535         EmpathyContactListViewPriv *priv;
536         GtkCellRenderer           *cell;
537         GtkTreeViewColumn         *col;
538         gint                       i;
539
540         priv = GET_PRIV (view);
541
542         gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view),
543                                              empathy_contact_list_store_search_equal_func,
544                                              NULL, NULL);
545
546         g_signal_connect (priv->store, "row-has-child-toggled",
547                           G_CALLBACK (contact_list_view_row_has_child_toggled_cb),
548                           view);
549         gtk_tree_view_set_model (GTK_TREE_VIEW (view),
550                                  GTK_TREE_MODEL (priv->store));
551
552         /* Setup view */
553         g_object_set (view,
554                       "headers-visible", FALSE,
555                       "reorderable", TRUE,
556                       "show-expanders", FALSE,
557                       NULL);
558
559         col = gtk_tree_view_column_new ();
560
561         /* State */
562         cell = gtk_cell_renderer_pixbuf_new ();
563         gtk_tree_view_column_pack_start (col, cell, FALSE);
564         gtk_tree_view_column_set_cell_data_func (
565                 col, cell,
566                 (GtkTreeCellDataFunc) contact_list_view_pixbuf_cell_data_func,
567                 view, NULL);
568
569         g_object_set (cell,
570                       "xpad", 5,
571                       "ypad", 1,
572                       "visible", FALSE,
573                       NULL);
574
575         /* Name */
576         cell = empathy_cell_renderer_text_new ();
577         gtk_tree_view_column_pack_start (col, cell, TRUE);
578         gtk_tree_view_column_set_cell_data_func (
579                 col, cell,
580                 (GtkTreeCellDataFunc) contact_list_view_text_cell_data_func,
581                 view, NULL);
582
583         gtk_tree_view_column_add_attribute (col, cell,
584                                             "name", COL_NAME);
585         gtk_tree_view_column_add_attribute (col, cell,
586                                             "status", COL_STATUS);
587         gtk_tree_view_column_add_attribute (col, cell,
588                                             "is_group", COL_IS_GROUP);
589
590         /* Voip Capability Icon */
591         cell = empathy_cell_renderer_activatable_new ();
592         gtk_tree_view_column_pack_start (col, cell, FALSE);
593         gtk_tree_view_column_set_cell_data_func (
594                 col, cell,
595                 (GtkTreeCellDataFunc) contact_list_view_voip_cell_data_func,
596                 view, NULL);
597
598         g_object_set (cell,
599                       "visible", FALSE,
600                       NULL);
601
602         g_signal_connect (cell, "path-activated",
603                           G_CALLBACK (contact_list_view_voip_activated_cb),
604                           view);
605
606         /* Avatar */
607         cell = gtk_cell_renderer_pixbuf_new ();
608         gtk_tree_view_column_pack_start (col, cell, FALSE);
609         gtk_tree_view_column_set_cell_data_func (
610                 col, cell,
611                 (GtkTreeCellDataFunc) contact_list_view_avatar_cell_data_func,
612                 view, NULL);
613
614         g_object_set (cell,
615                       "xpad", 0,
616                       "ypad", 0,
617                       "visible", FALSE,
618                       "width", 32,
619                       "height", 32,
620                       NULL);
621
622         /* Expander */
623         cell = empathy_cell_renderer_expander_new ();
624         gtk_tree_view_column_pack_end (col, cell, FALSE);
625         gtk_tree_view_column_set_cell_data_func (
626                 col, cell,
627                 (GtkTreeCellDataFunc) contact_list_view_expander_cell_data_func,
628                 view, NULL);
629
630         /* Actually add the column now we have added all cell renderers */
631         gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
632
633         /* Drag & Drop. */
634         for (i = 0; i < G_N_ELEMENTS (drag_types_dest); ++i) {
635                 drag_atoms_dest[i] = gdk_atom_intern (drag_types_dest[i].target,
636                                                       FALSE);
637         }
638
639         for (i = 0; i < G_N_ELEMENTS (drag_types_source); ++i) {
640                 drag_atoms_source[i] = gdk_atom_intern (drag_types_source[i].target,
641                                                         FALSE);
642         }
643
644         /* Note: We support the COPY action too, but need to make the
645          * MOVE action the default.
646          */
647         gtk_drag_source_set (GTK_WIDGET (view),
648                              GDK_BUTTON1_MASK,
649                              drag_types_source,
650                              G_N_ELEMENTS (drag_types_source),
651                              GDK_ACTION_MOVE | GDK_ACTION_COPY);
652
653         gtk_drag_dest_set (GTK_WIDGET (view),
654                            GTK_DEST_DEFAULT_ALL,
655                            drag_types_dest,
656                            G_N_ELEMENTS (drag_types_dest),
657                            GDK_ACTION_MOVE | GDK_ACTION_COPY);
658 }
659
660 static void
661 contact_list_view_row_has_child_toggled_cb (GtkTreeModel          *model,
662                                             GtkTreePath           *path,
663                                             GtkTreeIter           *iter,
664                                             EmpathyContactListView *view)
665 {
666         gboolean  is_group = FALSE;
667         gchar    *name = NULL;
668
669         gtk_tree_model_get (model, iter,
670                             COL_IS_GROUP, &is_group,
671                             COL_NAME, &name,
672                             -1);
673
674         if (!is_group || G_STR_EMPTY (name)) {
675                 g_free (name);
676                 return;
677         }
678
679         if (empathy_contact_group_get_expanded (name)) {
680                 g_signal_handlers_block_by_func (view,
681                                                  contact_list_view_row_expand_or_collapse_cb,
682                                                  GINT_TO_POINTER (TRUE));
683                 gtk_tree_view_expand_row (GTK_TREE_VIEW (view), path, TRUE);
684                 g_signal_handlers_unblock_by_func (view,
685                                                    contact_list_view_row_expand_or_collapse_cb,
686                                                    GINT_TO_POINTER (TRUE));
687         } else {
688                 g_signal_handlers_block_by_func (view,
689                                                  contact_list_view_row_expand_or_collapse_cb,
690                                                  GINT_TO_POINTER (FALSE));
691                 gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), path);
692                 g_signal_handlers_unblock_by_func (view,
693                                                    contact_list_view_row_expand_or_collapse_cb,
694                                                    GINT_TO_POINTER (FALSE));
695         }
696
697         g_free (name);
698 }
699
700 static void
701 contact_list_view_drag_data_received (GtkWidget         *widget,
702                                       GdkDragContext    *context,
703                                       gint               x,
704                                       gint               y,
705                                       GtkSelectionData  *selection,
706                                       guint              info,
707                                       guint              time)
708 {
709         EmpathyContactListViewPriv *priv;
710         EmpathyContactList         *list;
711         EmpathyContactFactory      *factory;
712         McAccount                  *account;
713         GtkTreeModel               *model;
714         GtkTreePath                *path;
715         GtkTreeViewDropPosition     position;
716         EmpathyContact             *contact = NULL;
717         const gchar                *id;
718         gchar                     **strv;
719         gchar                      *new_group = NULL;
720         gchar                      *old_group = NULL;
721         gboolean                    is_row;
722
723         priv = GET_PRIV (widget);
724
725         id = (const gchar*) selection->data;
726         empathy_debug (DEBUG_DOMAIN, "Received %s%s drag & drop contact from roster with id:'%s'",
727                       context->action == GDK_ACTION_MOVE ? "move" : "",
728                       context->action == GDK_ACTION_COPY ? "copy" : "",
729                       id);
730
731         strv = g_strsplit (id, "/", 2);
732         factory = empathy_contact_factory_new ();
733         account = mc_account_lookup (strv[0]);
734         if (account) {
735                 contact = empathy_contact_factory_get_from_id (factory,
736                                                                account,
737                                                                strv[1]);
738                 g_object_unref (account);
739         }
740         g_object_unref (factory);
741         g_object_unref (account);
742         g_strfreev (strv);
743
744         if (!contact) {
745                 empathy_debug (DEBUG_DOMAIN, "No contact found associated with drag & drop");
746                 return;
747         }
748
749         model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
750
751         /* Get source group information. */
752         if (priv->drag_row) {
753                 path = gtk_tree_row_reference_get_path (priv->drag_row);
754                 if (path) {
755                         old_group = empathy_contact_list_store_get_parent_group (model, path, NULL);
756                         gtk_tree_path_free (path);
757                 }
758         }
759
760         /* Get destination group information. */
761         is_row = gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
762                                                     x,
763                                                     y,
764                                                     &path,
765                                                     &position);
766
767         if (is_row) {
768                 new_group = empathy_contact_list_store_get_parent_group (model, path, NULL);
769                 gtk_tree_path_free (path);
770         }
771
772         empathy_debug (DEBUG_DOMAIN,
773                       "contact %s (%d) dragged from '%s' to '%s'",
774                       empathy_contact_get_id (contact),
775                       empathy_contact_get_handle (contact),
776                       old_group, new_group);
777
778         list = empathy_contact_list_store_get_list_iface (priv->store);
779         if (new_group) {
780                 empathy_contact_list_add_to_group (list, contact, new_group);
781         }
782         if (old_group && context->action == GDK_ACTION_MOVE) {  
783                 empathy_contact_list_remove_from_group (list, contact, old_group);
784         }
785
786         g_free (old_group);
787         g_free (new_group);
788
789         gtk_drag_finish (context, TRUE, FALSE, GDK_CURRENT_TIME);
790 }
791
792 static gboolean
793 contact_list_view_drag_motion (GtkWidget      *widget,
794                                GdkDragContext *context,
795                                gint            x,
796                                gint            y,
797                                guint           time)
798 {
799         static DragMotionData *dm = NULL;
800         GtkTreePath           *path;
801         gboolean               is_row;
802         gboolean               is_different = FALSE;
803         gboolean               cleanup = TRUE;
804
805         is_row = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
806                                                 x,
807                                                 y,
808                                                 &path,
809                                                 NULL,
810                                                 NULL,
811                                                 NULL);
812
813         cleanup &= (!dm);
814
815         if (is_row) {
816                 cleanup &= (dm && gtk_tree_path_compare (dm->path, path) != 0);
817                 is_different = (!dm || (dm && gtk_tree_path_compare (dm->path, path) != 0));
818         } else {
819                 cleanup &= FALSE;
820         }
821
822         if (!is_different && !cleanup) {
823                 return TRUE;
824         }
825
826         if (dm) {
827                 gtk_tree_path_free (dm->path);
828                 if (dm->timeout_id) {
829                         g_source_remove (dm->timeout_id);
830                 }
831
832                 g_free (dm);
833
834                 dm = NULL;
835         }
836
837         if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) {
838                 dm = g_new0 (DragMotionData, 1);
839
840                 dm->view = EMPATHY_CONTACT_LIST_VIEW (widget);
841                 dm->path = gtk_tree_path_copy (path);
842
843                 dm->timeout_id = g_timeout_add (
844                         1500,
845                         (GSourceFunc) contact_list_view_drag_motion_cb,
846                         dm);
847         }
848
849         return TRUE;
850 }
851
852 static gboolean
853 contact_list_view_drag_motion_cb (DragMotionData *data)
854 {
855         gtk_tree_view_expand_row (GTK_TREE_VIEW (data->view),
856                                   data->path,
857                                   FALSE);
858
859         data->timeout_id = 0;
860
861         return FALSE;
862 }
863
864 static void
865 contact_list_view_drag_begin (GtkWidget      *widget,
866                               GdkDragContext *context)
867 {
868         EmpathyContactListViewPriv *priv;
869         GtkTreeSelection          *selection;
870         GtkTreeModel              *model;
871         GtkTreePath               *path;
872         GtkTreeIter                iter;
873
874         priv = GET_PRIV (widget);
875
876         GTK_WIDGET_CLASS (empathy_contact_list_view_parent_class)->drag_begin (widget,
877                                                                               context);
878
879         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
880         if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
881                 return;
882         }
883
884         path = gtk_tree_model_get_path (model, &iter);
885         priv->drag_row = gtk_tree_row_reference_new (model, path);
886         gtk_tree_path_free (path);
887 }
888
889 static void
890 contact_list_view_drag_data_get (GtkWidget        *widget,
891                                  GdkDragContext   *context,
892                                  GtkSelectionData *selection,
893                                  guint             info,
894                                  guint             time)
895 {
896         EmpathyContactListViewPriv *priv;
897         GtkTreePath                *src_path;
898         GtkTreeIter                 iter;
899         GtkTreeModel               *model;
900         EmpathyContact             *contact;
901         McAccount                  *account;
902         const gchar                *contact_id;
903         const gchar                *account_id;
904         gchar                      *str;
905         
906
907         priv = GET_PRIV (widget);
908
909         model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
910         if (!priv->drag_row) {
911                 return;
912         }
913
914         src_path = gtk_tree_row_reference_get_path (priv->drag_row);
915         if (!src_path) {
916                 return;
917         }
918
919         if (!gtk_tree_model_get_iter (model, &iter, src_path)) {
920                 gtk_tree_path_free (src_path);
921                 return;
922         }
923
924         gtk_tree_path_free (src_path);
925
926         contact = empathy_contact_list_view_get_selected (EMPATHY_CONTACT_LIST_VIEW (widget));
927         if (!contact) {
928                 return;
929         }
930
931         account = empathy_contact_get_account (contact);
932         account_id = mc_account_get_unique_name (account);
933         contact_id = empathy_contact_get_id (contact);
934         g_object_unref (contact);
935         str = g_strconcat (account_id, "/", contact_id, NULL);
936
937         switch (info) {
938         case DND_DRAG_TYPE_CONTACT_ID:
939                 gtk_selection_data_set (selection, drag_atoms_source[info], 8,
940                                         (guchar*)str, strlen (str) + 1);
941                 break;
942         }
943
944         g_free (str);
945 }
946
947 static void
948 contact_list_view_drag_end (GtkWidget      *widget,
949                             GdkDragContext *context)
950 {
951         EmpathyContactListViewPriv *priv;
952
953         priv = GET_PRIV (widget);
954
955         GTK_WIDGET_CLASS (empathy_contact_list_view_parent_class)->drag_end (widget,
956                                                                             context);
957
958         if (priv->drag_row) {
959                 gtk_tree_row_reference_free (priv->drag_row);
960                 priv->drag_row = NULL;
961         }
962 }
963
964 static gboolean
965 contact_list_view_drag_drop (GtkWidget      *widget,
966                              GdkDragContext *drag_context,
967                              gint            x,
968                              gint            y,
969                              guint           time)
970 {
971         return FALSE;
972 }
973
974 static void
975 contact_list_view_cell_set_background (EmpathyContactListView *view,
976                                        GtkCellRenderer       *cell,
977                                        gboolean               is_group,
978                                        gboolean               is_active)
979 {
980         GdkColor  color;
981         GtkStyle *style;
982
983         style = gtk_widget_get_style (GTK_WIDGET (view));
984
985         if (!is_group) {
986                 if (is_active) {
987                         color = style->bg[GTK_STATE_SELECTED];
988
989                         /* Here we take the current theme colour and add it to
990                          * the colour for white and average the two. This
991                          * gives a colour which is inline with the theme but
992                          * slightly whiter.
993                          */
994                         color.red = (color.red + (style->white).red) / 2;
995                         color.green = (color.green + (style->white).green) / 2;
996                         color.blue = (color.blue + (style->white).blue) / 2;
997
998                         g_object_set (cell,
999                                       "cell-background-gdk", &color,
1000                                       NULL);
1001                 } else {
1002                         g_object_set (cell,
1003                                       "cell-background-gdk", NULL,
1004                                       NULL);
1005                 }
1006         } else {
1007                 g_object_set (cell,
1008                               "cell-background-gdk", NULL,
1009                               NULL);
1010         }
1011 }
1012
1013 static void
1014 contact_list_view_pixbuf_cell_data_func (GtkTreeViewColumn     *tree_column,
1015                                          GtkCellRenderer       *cell,
1016                                          GtkTreeModel          *model,
1017                                          GtkTreeIter           *iter,
1018                                          EmpathyContactListView *view)
1019 {
1020         gchar    *icon_name;
1021         gboolean  is_group;
1022         gboolean  is_active;
1023
1024         gtk_tree_model_get (model, iter,
1025                             COL_IS_GROUP, &is_group,
1026                             COL_IS_ACTIVE, &is_active,
1027                             COL_ICON_STATUS, &icon_name,
1028                             -1);
1029
1030         g_object_set (cell,
1031                       "visible", !is_group,
1032                       "icon-name", icon_name,
1033                       NULL);
1034
1035         g_free (icon_name);
1036
1037         contact_list_view_cell_set_background (view, cell, is_group, is_active);
1038 }
1039
1040 static void
1041 contact_list_view_voip_cell_data_func (GtkTreeViewColumn      *tree_column,
1042                                        GtkCellRenderer        *cell,
1043                                        GtkTreeModel           *model,
1044                                        GtkTreeIter            *iter,
1045                                        EmpathyContactListView *view)
1046 {
1047         gboolean is_group;
1048         gboolean is_active;
1049         gboolean can_voip;
1050
1051         gtk_tree_model_get (model, iter,
1052                             COL_IS_GROUP, &is_group,
1053                             COL_IS_ACTIVE, &is_active,
1054                             COL_CAN_VOIP, &can_voip,
1055                             -1);
1056
1057         g_object_set (cell,
1058                       "visible", !is_group && can_voip,
1059                       "icon-name", EMPATHY_IMAGE_VOIP,
1060                       NULL);
1061
1062         contact_list_view_cell_set_background (view, cell, is_group, is_active);
1063 }
1064
1065 static void
1066 contact_list_view_avatar_cell_data_func (GtkTreeViewColumn     *tree_column,
1067                                          GtkCellRenderer       *cell,
1068                                          GtkTreeModel          *model,
1069                                          GtkTreeIter           *iter,
1070                                          EmpathyContactListView *view)
1071 {
1072         GdkPixbuf *pixbuf;
1073         gboolean   show_avatar;
1074         gboolean   is_group;
1075         gboolean   is_active;
1076
1077         gtk_tree_model_get (model, iter,
1078                             COL_PIXBUF_AVATAR, &pixbuf,
1079                             COL_PIXBUF_AVATAR_VISIBLE, &show_avatar,
1080                             COL_IS_GROUP, &is_group,
1081                             COL_IS_ACTIVE, &is_active,
1082                             -1);
1083
1084         g_object_set (cell,
1085                       "visible", !is_group && show_avatar,
1086                       "pixbuf", pixbuf,
1087                       NULL);
1088
1089         if (pixbuf) {
1090                 g_object_unref (pixbuf);
1091         }
1092
1093         contact_list_view_cell_set_background (view, cell, is_group, is_active);
1094 }
1095
1096 static void
1097 contact_list_view_text_cell_data_func (GtkTreeViewColumn     *tree_column,
1098                                        GtkCellRenderer       *cell,
1099                                        GtkTreeModel          *model,
1100                                        GtkTreeIter           *iter,
1101                                        EmpathyContactListView *view)
1102 {
1103         gboolean is_group;
1104         gboolean is_active;
1105         gboolean show_status;
1106
1107         gtk_tree_model_get (model, iter,
1108                             COL_IS_GROUP, &is_group,
1109                             COL_IS_ACTIVE, &is_active,
1110                             COL_STATUS_VISIBLE, &show_status,
1111                             -1);
1112
1113         g_object_set (cell,
1114                       "show-status", show_status,
1115                       NULL);
1116
1117         contact_list_view_cell_set_background (view, cell, is_group, is_active);
1118 }
1119
1120 static void
1121 contact_list_view_expander_cell_data_func (GtkTreeViewColumn     *column,
1122                                            GtkCellRenderer       *cell,
1123                                            GtkTreeModel          *model,
1124                                            GtkTreeIter           *iter,
1125                                            EmpathyContactListView *view)
1126 {
1127         gboolean is_group;
1128         gboolean is_active;
1129
1130         gtk_tree_model_get (model, iter,
1131                             COL_IS_GROUP, &is_group,
1132                             COL_IS_ACTIVE, &is_active,
1133                             -1);
1134
1135         if (gtk_tree_model_iter_has_child (model, iter)) {
1136                 GtkTreePath *path;
1137                 gboolean     row_expanded;
1138
1139                 path = gtk_tree_model_get_path (model, iter);
1140                 row_expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (column->tree_view), path);
1141                 gtk_tree_path_free (path);
1142
1143                 g_object_set (cell,
1144                               "visible", TRUE,
1145                               "expander-style", row_expanded ? GTK_EXPANDER_EXPANDED : GTK_EXPANDER_COLLAPSED,
1146                               NULL);
1147         } else {
1148                 g_object_set (cell, "visible", FALSE, NULL);
1149         }
1150
1151         contact_list_view_cell_set_background (view, cell, is_group, is_active);
1152 }
1153
1154 static GtkWidget *
1155 contact_list_view_get_contact_menu (EmpathyContactListView *view,
1156                                     gboolean               can_send_file,
1157                                     gboolean               can_show_log,
1158                                     gboolean               can_voip)
1159 {
1160         EmpathyContactListViewPriv *priv;
1161         GtkAction                 *action;
1162         GtkWidget                 *widget;
1163
1164         priv = GET_PRIV (view);
1165
1166         /* Sort out sensitive items */
1167         action = gtk_ui_manager_get_action (priv->ui, "/Contact/Log");
1168         gtk_action_set_sensitive (action, can_show_log);
1169
1170         action = gtk_ui_manager_get_action (priv->ui, "/Contact/Call");
1171         gtk_action_set_sensitive (action, can_voip);
1172
1173         action = gtk_ui_manager_get_action (priv->ui, "/Contact/SendFile");
1174         gtk_action_set_visible (action, can_send_file);
1175
1176         widget = gtk_ui_manager_get_widget (priv->ui, "/Contact");
1177
1178         return widget;
1179 }
1180
1181 static gboolean
1182 contact_list_view_button_press_event_cb (EmpathyContactListView *view,
1183                                          GdkEventButton        *event,
1184                                          gpointer               user_data)
1185 {
1186         EmpathyContactListViewPriv *priv;
1187         EmpathyContact             *contact;
1188         GtkTreePath               *path;
1189         GtkTreeSelection          *selection;
1190         GtkTreeModel              *model;
1191         GtkTreeIter                iter;
1192         gboolean                   row_exists;
1193         GtkWidget                 *menu;
1194
1195         if (event->button != 3) {
1196                 return FALSE;
1197         }
1198
1199         priv = GET_PRIV (view);
1200
1201         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1202         model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1203
1204         gtk_widget_grab_focus (GTK_WIDGET (view));
1205
1206         row_exists = gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view),
1207                                                     event->x, event->y,
1208                                                     &path,
1209                                                     NULL, NULL, NULL);
1210         if (!row_exists) {
1211                 return FALSE;
1212         }
1213
1214         gtk_tree_selection_unselect_all (selection);
1215         gtk_tree_selection_select_path (selection, path);
1216
1217         gtk_tree_model_get_iter (model, &iter, path);
1218         gtk_tree_path_free (path);
1219
1220         gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1);
1221
1222         if (contact) {
1223                 menu = empathy_contact_list_view_get_contact_menu (view, contact);
1224                 g_object_unref (contact);
1225         } else {
1226                 menu = empathy_contact_list_view_get_group_menu (view);
1227         }
1228
1229         if (!menu) {
1230                 return FALSE;
1231         }
1232
1233         gtk_widget_show (menu);
1234
1235         gtk_menu_popup (GTK_MENU (menu),
1236                         NULL, NULL, NULL, NULL,
1237                         event->button, event->time);
1238
1239         return TRUE;
1240 }
1241
1242 static void
1243 contact_list_view_row_activated_cb (EmpathyContactListView *view,
1244                                     GtkTreePath           *path,
1245                                     GtkTreeViewColumn     *col,
1246                                     gpointer               user_data)
1247 {
1248         EmpathyContact *contact;
1249         GtkTreeModel  *model;
1250         GtkTreeIter    iter;
1251
1252         model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1253
1254         gtk_tree_model_get_iter (model, &iter, path);
1255         gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1);
1256
1257         if (contact) {
1258                 contact_list_view_action_activated (view, contact);
1259                 g_object_unref (contact);
1260         }
1261 }
1262
1263 static void
1264 contact_list_view_voip_activated_cb (EmpathyCellRendererActivatable *cell,
1265                                      const gchar                    *path_string,
1266                                      EmpathyContactListView         *view)
1267 {
1268         GtkTreeModel   *model;
1269         GtkTreeIter     iter;
1270         EmpathyContact *contact;
1271
1272         model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1273         if (!gtk_tree_model_get_iter_from_string (model, &iter, path_string)) {
1274                 return;
1275         }
1276
1277         gtk_tree_model_get (model, &iter, COL_CONTACT, &contact, -1);
1278
1279         if (contact) {
1280                 contact_list_view_voip_activated (view, contact);
1281                 g_object_unref (contact);
1282         }
1283 }
1284
1285
1286 static void
1287 contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView *view,
1288                                              GtkTreeIter           *iter,
1289                                              GtkTreePath           *path,
1290                                              gpointer               user_data)
1291 {
1292         GtkTreeModel *model;
1293         gchar        *name;
1294         gboolean      expanded;
1295
1296         model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1297
1298         gtk_tree_model_get (model, iter,
1299                             COL_NAME, &name,
1300                             -1);
1301
1302         expanded = GPOINTER_TO_INT (user_data);
1303         empathy_contact_group_set_expanded (name, expanded);
1304
1305         g_free (name);
1306 }
1307
1308 static void
1309 contact_list_view_action_cb (GtkAction             *action,
1310                              EmpathyContactListView *view)
1311 {
1312         EmpathyContactListViewPriv *priv;
1313         EmpathyContact             *contact;
1314         const gchar               *name;
1315         gchar                     *group;
1316         GtkWindow                 *parent;
1317
1318         priv = GET_PRIV (view);
1319
1320         name = gtk_action_get_name (action);
1321         if (!name) {
1322                 return;
1323         }
1324
1325         empathy_debug (DEBUG_DOMAIN, "Action:'%s' activated", name);
1326
1327         contact = empathy_contact_list_view_get_selected (view);
1328         group = empathy_contact_list_view_get_selected_group (view);
1329         parent = empathy_get_toplevel_window (GTK_WIDGET (view));
1330
1331         if (contact && strcmp (name, "Chat") == 0) {
1332                 contact_list_view_action_activated (view, contact);
1333         }
1334         else if (contact && strcmp (name, "Call") == 0) {
1335                 contact_list_view_voip_activated (view, contact);
1336         }
1337         else if (contact && strcmp (name, "Information") == 0) {
1338                 empathy_contact_information_dialog_show (contact, parent, FALSE);
1339         }
1340         else if (contact && strcmp (name, "Edit") == 0) {
1341                 empathy_contact_information_dialog_show (contact, parent, TRUE);
1342         }
1343         else if (contact && strcmp (name, "Remove") == 0) {
1344                 /* FIXME: Ask for confirmation */
1345                 EmpathyContactList *list;
1346
1347                 list = empathy_contact_list_store_get_list_iface (priv->store);
1348                 empathy_contact_list_remove (list, contact,
1349                                              _("Sorry, I don't want you in my contact list anymore."));
1350         }
1351         else if (contact && strcmp (name, "Invite") == 0) {
1352         }
1353         else if (contact && strcmp (name, "SendFile") == 0) {
1354         }
1355         else if (contact && strcmp (name, "Log") == 0) {
1356                 empathy_log_window_show (empathy_contact_get_account (contact),
1357                                         empathy_contact_get_id (contact),
1358                                         FALSE,
1359                                         parent);
1360         }
1361         else if (group && strcmp (name, "Rename") == 0) {
1362         }
1363
1364         g_free (group);
1365         if (contact) {
1366                 g_object_unref (contact);
1367         }
1368 }
1369
1370 static void
1371 contact_list_view_action_activated (EmpathyContactListView *view,
1372                                     EmpathyContact         *contact)
1373 {
1374         MissionControl *mc;
1375
1376         mc = empathy_mission_control_new ();
1377         mission_control_request_channel (mc,
1378                                          empathy_contact_get_account (contact),
1379                                          TP_IFACE_CHANNEL_TYPE_TEXT,
1380                                          empathy_contact_get_handle (contact),
1381                                          TP_HANDLE_TYPE_CONTACT,
1382                                          NULL, NULL);
1383         g_object_unref (mc);
1384 }
1385
1386 static void
1387 contact_list_view_voip_activated (EmpathyContactListView *view,
1388                                   EmpathyContact         *contact)
1389 {
1390         MissionControl *mc;
1391
1392         mc = empathy_mission_control_new ();
1393         mission_control_request_channel (mc,
1394                                          empathy_contact_get_account (contact),
1395                                          TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA,
1396                                          empathy_contact_get_handle (contact),
1397                                          TP_HANDLE_TYPE_CONTACT,
1398                                          NULL, NULL);
1399         g_object_unref (mc);
1400 }
1401