1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2005-2007 Imendio AB
4 * Copyright (C) 2007-2008 Collabora Ltd.
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.
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.
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., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 * Authors: Mikael Hallendal <micke@imendio.com>
22 * Martyn Russell <martyn@imendio.com>
23 * Xavier Claessens <xclaesse@gmail.com>
30 #include <glib/gi18n-lib.h>
31 #include <gdk/gdkkeysyms.h>
34 #include <telepathy-glib/account-manager.h>
35 #include <telepathy-glib/util.h>
37 #include <extensions/extensions.h>
38 #include <libempathy/empathy-call-factory.h>
39 #include <libempathy/empathy-tp-contact-factory.h>
40 #include <libempathy/empathy-contact-list.h>
41 #include <libempathy/empathy-contact-groups.h>
42 #include <libempathy/empathy-dispatcher.h>
43 #include <libempathy/empathy-utils.h>
45 #include "empathy-contact-list-view.h"
46 #include "empathy-contact-list-store.h"
47 #include "empathy-images.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-gtk-enum-types.h"
53 #include "empathy-gtk-marshal.h"
55 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
56 #include <libempathy/empathy-debug.h>
58 /* Active users are those which have recently changed state
59 * (e.g. online, offline or from normal to a busy state).
62 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactListView)
64 EmpathyContactListStore
*store
;
65 GtkTreeRowReference
*drag_row
;
66 EmpathyContactListFeatureFlags list_features
;
67 EmpathyContactFeatureFlags contact_features
;
68 GtkWidget
*tooltip_widget
;
69 GtkTargetList
*file_targets
;
70 } EmpathyContactListViewPriv
;
73 EmpathyContactListView
*view
;
79 EmpathyContactListView
*view
;
80 EmpathyContact
*contact
;
88 PROP_CONTACT_FEATURES
,
92 DND_DRAG_TYPE_CONTACT_ID
,
93 DND_DRAG_TYPE_URI_LIST
,
97 static const GtkTargetEntry drag_types_dest
[] = {
98 { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST
},
99 { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID
},
100 { "text/plain", 0, DND_DRAG_TYPE_STRING
},
101 { "STRING", 0, DND_DRAG_TYPE_STRING
},
104 static const GtkTargetEntry drag_types_dest_file
[] = {
105 { "text/uri-list", 0, DND_DRAG_TYPE_URI_LIST
},
108 static const GtkTargetEntry drag_types_source
[] = {
109 { "text/contact-id", 0, DND_DRAG_TYPE_CONTACT_ID
},
112 static GdkAtom drag_atoms_dest
[G_N_ELEMENTS (drag_types_dest
)];
113 static GdkAtom drag_atoms_source
[G_N_ELEMENTS (drag_types_source
)];
116 DRAG_CONTACT_RECEIVED
,
120 static guint signals
[LAST_SIGNAL
];
122 G_DEFINE_TYPE (EmpathyContactListView
, empathy_contact_list_view
, GTK_TYPE_TREE_VIEW
);
125 contact_list_view_tooltip_destroy_cb (GtkWidget
*widget
,
126 EmpathyContactListView
*view
)
128 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
130 if (priv
->tooltip_widget
) {
131 DEBUG ("Tooltip destroyed");
132 g_object_unref (priv
->tooltip_widget
);
133 priv
->tooltip_widget
= NULL
;
138 contact_list_view_query_tooltip_cb (EmpathyContactListView
*view
,
141 gboolean keyboard_mode
,
145 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
146 EmpathyContact
*contact
;
150 static gint running
= 0;
151 gboolean ret
= FALSE
;
153 /* Avoid an infinite loop. See GNOME bug #574377 */
159 /* Don't show the tooltip if there's already a popup menu */
160 if (gtk_menu_get_for_attach_widget (GTK_WIDGET (view
)) != NULL
) {
164 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (view
), &x
, &y
,
166 &model
, &path
, &iter
)) {
170 gtk_tree_view_set_tooltip_row (GTK_TREE_VIEW (view
), tooltip
, path
);
171 gtk_tree_path_free (path
);
173 gtk_tree_model_get (model
, &iter
,
174 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
180 if (!priv
->tooltip_widget
) {
181 priv
->tooltip_widget
= empathy_contact_widget_new (contact
,
182 EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP
|
183 EMPATHY_CONTACT_WIDGET_SHOW_LOCATION
);
184 gtk_container_set_border_width (
185 GTK_CONTAINER (priv
->tooltip_widget
), 8);
186 g_object_ref (priv
->tooltip_widget
);
187 g_signal_connect (priv
->tooltip_widget
, "destroy",
188 G_CALLBACK (contact_list_view_tooltip_destroy_cb
),
190 gtk_widget_show (priv
->tooltip_widget
);
192 empathy_contact_widget_set_contact (priv
->tooltip_widget
,
196 gtk_tooltip_set_custom (tooltip
, priv
->tooltip_widget
);
199 g_object_unref (contact
);
209 GdkDragAction action
;
213 contact_list_view_dnd_get_contact_free (DndGetContactData
*data
)
215 g_free (data
->new_group
);
216 g_free (data
->old_group
);
217 g_slice_free (DndGetContactData
, data
);
221 contact_list_view_drag_got_contact (EmpathyTpContactFactory
*factory
,
222 EmpathyContact
*contact
,
227 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
228 DndGetContactData
*data
= user_data
;
229 EmpathyContactList
*list
;
232 DEBUG ("Error: %s", error
->message
);
236 DEBUG ("contact %s (%d) dragged from '%s' to '%s'",
237 empathy_contact_get_id (contact
),
238 empathy_contact_get_handle (contact
),
239 data
->old_group
, data
->new_group
);
241 list
= empathy_contact_list_store_get_list_iface (priv
->store
);
242 if (data
->new_group
) {
243 empathy_contact_list_add_to_group (list
, contact
, data
->new_group
);
245 if (data
->old_group
&& data
->action
== GDK_ACTION_MOVE
) {
246 empathy_contact_list_remove_from_group (list
, contact
, data
->old_group
);
251 contact_list_view_contact_drag_received (GtkWidget
*view
,
252 GdkDragContext
*context
,
255 GtkSelectionData
*selection
)
257 EmpathyContactListViewPriv
*priv
;
258 TpAccountManager
*account_manager
;
259 EmpathyTpContactFactory
*factory
= NULL
;
261 DndGetContactData
*data
;
262 GtkTreePath
*source_path
;
263 const gchar
*sel_data
;
265 const gchar
*account_id
= NULL
;
266 const gchar
*contact_id
= NULL
;
267 gchar
*new_group
= NULL
;
268 gchar
*old_group
= NULL
;
269 gboolean success
= TRUE
;
271 priv
= GET_PRIV (view
);
273 sel_data
= (const gchar
*) gtk_selection_data_get_data (selection
);
274 new_group
= empathy_contact_list_store_get_parent_group (model
,
277 /* Get source group information. */
278 if (priv
->drag_row
) {
279 source_path
= gtk_tree_row_reference_get_path (priv
->drag_row
);
281 old_group
= empathy_contact_list_store_get_parent_group (
282 model
, source_path
, NULL
);
283 gtk_tree_path_free (source_path
);
287 if (!tp_strdiff (old_group
, new_group
)) {
293 account_manager
= tp_account_manager_dup ();
294 strv
= g_strsplit (sel_data
, ":", 2);
295 if (g_strv_length (strv
) == 2) {
296 account_id
= strv
[0];
297 contact_id
= strv
[1];
298 account
= tp_account_manager_ensure_account (account_manager
, account_id
);
301 TpConnection
*connection
;
303 connection
= tp_account_get_connection (account
);
305 factory
= empathy_tp_contact_factory_dup_singleton (connection
);
308 g_object_unref (account_manager
);
311 DEBUG ("Failed to get factory for account '%s'", account_id
);
318 data
= g_slice_new0 (DndGetContactData
);
319 data
->new_group
= new_group
;
320 data
->old_group
= old_group
;
321 data
->action
= context
->action
;
323 /* FIXME: We should probably wait for the cb before calling
325 empathy_tp_contact_factory_get_from_id (factory
, contact_id
,
326 contact_list_view_drag_got_contact
,
327 data
, (GDestroyNotify
) contact_list_view_dnd_get_contact_free
,
330 g_object_unref (factory
);
336 contact_list_view_file_drag_received (GtkWidget
*view
,
337 GdkDragContext
*context
,
340 GtkSelectionData
*selection
)
343 const gchar
*sel_data
;
344 EmpathyContact
*contact
;
346 sel_data
= (const gchar
*) gtk_selection_data_get_data (selection
);
348 gtk_tree_model_get_iter (model
, &iter
, path
);
349 gtk_tree_model_get (model
, &iter
,
350 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
356 empathy_send_file_from_uri_list (contact
, sel_data
);
358 g_object_unref (contact
);
364 contact_list_view_drag_data_received (GtkWidget
*view
,
365 GdkDragContext
*context
,
368 GtkSelectionData
*selection
,
374 GtkTreeViewDropPosition position
;
376 gboolean success
= TRUE
;
378 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
380 /* Get destination group information. */
381 is_row
= gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (view
),
389 else if (info
== DND_DRAG_TYPE_CONTACT_ID
|| info
== DND_DRAG_TYPE_STRING
) {
390 success
= contact_list_view_contact_drag_received (view
,
396 else if (info
== DND_DRAG_TYPE_URI_LIST
) {
397 success
= contact_list_view_file_drag_received (view
,
404 gtk_tree_path_free (path
);
405 gtk_drag_finish (context
, success
, FALSE
, GDK_CURRENT_TIME
);
409 contact_list_view_drag_motion_cb (DragMotionData
*data
)
411 gtk_tree_view_expand_row (GTK_TREE_VIEW (data
->view
),
415 data
->timeout_id
= 0;
421 contact_list_view_drag_motion (GtkWidget
*widget
,
422 GdkDragContext
*context
,
427 EmpathyContactListViewPriv
*priv
;
431 static DragMotionData
*dm
= NULL
;
434 gboolean is_different
= FALSE
;
435 gboolean cleanup
= TRUE
;
436 gboolean retval
= TRUE
;
438 priv
= GET_PRIV (EMPATHY_CONTACT_LIST_VIEW (widget
));
439 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (widget
));
441 is_row
= gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget
),
452 cleanup
&= (dm
&& gtk_tree_path_compare (dm
->path
, path
) != 0);
453 is_different
= (!dm
|| (dm
&& gtk_tree_path_compare (dm
->path
, path
) != 0));
459 /* Coordinates don't point to an actual row, so make sure the pointer
460 and highlighting don't indicate that a drag is possible.
462 gdk_drag_status (context
, GDK_ACTION_DEFAULT
, time_
);
463 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget
), NULL
, 0);
466 target
= gtk_drag_dest_find_target (widget
, context
, priv
->file_targets
);
467 gtk_tree_model_get_iter (model
, &iter
, path
);
469 if (target
== GDK_NONE
) {
470 /* If target == GDK_NONE, then we don't have a target that can be
471 dropped on a contact. This means a contact drag. If we're
472 pointing to a group, highlight it. Otherwise, if the contact
473 we're pointing to is in a group, highlight that. Otherwise,
474 set the drag position to before the first row for a drag into
475 the "non-group" at the top.
477 GtkTreeIter group_iter
;
479 GtkTreePath
*group_path
;
480 gtk_tree_model_get (model
, &iter
,
481 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
487 if (gtk_tree_model_iter_parent (model
, &group_iter
, &iter
))
488 gtk_tree_model_get (model
, &group_iter
,
489 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
493 gdk_drag_status (context
, GDK_ACTION_MOVE
, time_
);
494 group_path
= gtk_tree_model_get_path (model
, &group_iter
);
495 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget
),
497 GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
);
498 gtk_tree_path_free (group_path
);
501 group_path
= gtk_tree_path_new_first ();
502 gdk_drag_status (context
, GDK_ACTION_MOVE
, time_
);
503 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget
),
505 GTK_TREE_VIEW_DROP_BEFORE
);
509 /* This is a file drag, and it can only be dropped on contacts,
512 EmpathyContact
*contact
;
513 gtk_tree_model_get (model
, &iter
,
514 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
516 if (contact
!= NULL
&&
517 empathy_contact_is_online (contact
) &&
518 (empathy_contact_get_capabilities (contact
) & EMPATHY_CAPABILITIES_FT
)) {
519 gdk_drag_status (context
, GDK_ACTION_COPY
, time_
);
520 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget
),
522 GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
);
523 g_object_unref (contact
);
526 gdk_drag_status (context
, 0, time_
);
527 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget
), NULL
, 0);
532 if (!is_different
&& !cleanup
) {
537 gtk_tree_path_free (dm
->path
);
538 if (dm
->timeout_id
) {
539 g_source_remove (dm
->timeout_id
);
547 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget
), path
)) {
548 dm
= g_new0 (DragMotionData
, 1);
550 dm
->view
= EMPATHY_CONTACT_LIST_VIEW (widget
);
551 dm
->path
= gtk_tree_path_copy (path
);
553 dm
->timeout_id
= g_timeout_add_seconds (1,
554 (GSourceFunc
) contact_list_view_drag_motion_cb
,
562 contact_list_view_drag_begin (GtkWidget
*widget
,
563 GdkDragContext
*context
)
565 EmpathyContactListViewPriv
*priv
;
566 GtkTreeSelection
*selection
;
571 priv
= GET_PRIV (widget
);
573 GTK_WIDGET_CLASS (empathy_contact_list_view_parent_class
)->drag_begin (widget
,
576 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (widget
));
577 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
581 path
= gtk_tree_model_get_path (model
, &iter
);
582 priv
->drag_row
= gtk_tree_row_reference_new (model
, path
);
583 gtk_tree_path_free (path
);
587 contact_list_view_drag_data_get (GtkWidget
*widget
,
588 GdkDragContext
*context
,
589 GtkSelectionData
*selection
,
593 EmpathyContactListViewPriv
*priv
;
594 GtkTreePath
*src_path
;
597 EmpathyContact
*contact
;
599 const gchar
*contact_id
;
600 const gchar
*account_id
;
603 priv
= GET_PRIV (widget
);
605 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (widget
));
606 if (!priv
->drag_row
) {
610 src_path
= gtk_tree_row_reference_get_path (priv
->drag_row
);
615 if (!gtk_tree_model_get_iter (model
, &iter
, src_path
)) {
616 gtk_tree_path_free (src_path
);
620 gtk_tree_path_free (src_path
);
622 contact
= empathy_contact_list_view_dup_selected (EMPATHY_CONTACT_LIST_VIEW (widget
));
627 account
= empathy_contact_get_account (contact
);
628 account_id
= tp_proxy_get_object_path (account
);
629 contact_id
= empathy_contact_get_id (contact
);
630 g_object_unref (contact
);
631 str
= g_strconcat (account_id
, ":", contact_id
, NULL
);
634 case DND_DRAG_TYPE_CONTACT_ID
:
635 gtk_selection_data_set (selection
, drag_atoms_source
[info
], 8,
636 (guchar
*) str
, strlen (str
) + 1);
644 contact_list_view_drag_end (GtkWidget
*widget
,
645 GdkDragContext
*context
)
647 EmpathyContactListViewPriv
*priv
;
649 priv
= GET_PRIV (widget
);
651 GTK_WIDGET_CLASS (empathy_contact_list_view_parent_class
)->drag_end (widget
,
654 if (priv
->drag_row
) {
655 gtk_tree_row_reference_free (priv
->drag_row
);
656 priv
->drag_row
= NULL
;
661 contact_list_view_drag_drop (GtkWidget
*widget
,
662 GdkDragContext
*drag_context
,
671 EmpathyContactListView
*view
;
677 contact_list_view_popup_menu_idle_cb (gpointer user_data
)
679 MenuPopupData
*data
= user_data
;
682 menu
= empathy_contact_list_view_get_contact_menu (data
->view
);
684 menu
= empathy_contact_list_view_get_group_menu (data
->view
);
688 g_signal_connect (menu
, "deactivate",
689 G_CALLBACK (gtk_menu_detach
), NULL
);
690 gtk_menu_attach_to_widget (GTK_MENU (menu
),
691 GTK_WIDGET (data
->view
), NULL
);
692 gtk_widget_show (menu
);
693 gtk_menu_popup (GTK_MENU (menu
),
694 NULL
, NULL
, NULL
, NULL
,
695 data
->button
, data
->time
);
696 g_object_ref_sink (menu
);
697 g_object_unref (menu
);
700 g_slice_free (MenuPopupData
, data
);
706 contact_list_view_button_press_event_cb (EmpathyContactListView
*view
,
707 GdkEventButton
*event
,
710 if (event
->button
== 3) {
713 data
= g_slice_new (MenuPopupData
);
715 data
->button
= event
->button
;
716 data
->time
= event
->time
;
717 g_idle_add (contact_list_view_popup_menu_idle_cb
, data
);
724 contact_list_view_key_press_event_cb (EmpathyContactListView
*view
,
728 if (event
->keyval
== GDK_Menu
) {
731 data
= g_slice_new (MenuPopupData
);
734 data
->time
= event
->time
;
735 g_idle_add (contact_list_view_popup_menu_idle_cb
, data
);
742 contact_list_view_row_activated (GtkTreeView
*view
,
744 GtkTreeViewColumn
*column
)
746 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
747 EmpathyContact
*contact
;
751 if (!(priv
->contact_features
& EMPATHY_CONTACT_FEATURE_CHAT
)) {
755 model
= GTK_TREE_MODEL (priv
->store
);
756 gtk_tree_model_get_iter (model
, &iter
, path
);
757 gtk_tree_model_get (model
, &iter
,
758 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
762 DEBUG ("Starting a chat");
763 empathy_dispatcher_chat_with_contact (contact
, NULL
, NULL
);
764 g_object_unref (contact
);
769 contact_list_view_call_activated_cb (
770 EmpathyCellRendererActivatable
*cell
,
771 const gchar
*path_string
,
772 EmpathyContactListView
*view
)
777 EmpathyContact
*contact
;
778 GdkEventButton
*event
;
782 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
783 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path_string
))
786 gtk_tree_model_get (model
, &iter
,
787 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
792 event
= (GdkEventButton
*) gtk_get_current_event ();
794 menu
= gtk_menu_new ();
795 shell
= GTK_MENU_SHELL (menu
);
798 item
= empathy_contact_audio_call_menu_item_new (contact
);
799 gtk_menu_shell_append (shell
, item
);
800 gtk_widget_show (item
);
803 item
= empathy_contact_video_call_menu_item_new (contact
);
804 gtk_menu_shell_append (shell
, item
);
805 gtk_widget_show (item
);
807 g_signal_connect (menu
, "deactivate",
808 G_CALLBACK (gtk_menu_detach
), NULL
);
809 gtk_menu_attach_to_widget (GTK_MENU (menu
),
810 GTK_WIDGET (view
), NULL
);
811 gtk_widget_show (menu
);
812 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
813 event
->button
, event
->time
);
814 g_object_ref_sink (menu
);
815 g_object_unref (menu
);
817 g_object_unref (contact
);
820 #if HAVE_FAVOURITE_CONTACTS
822 contact_list_view_favourite_toggled_cb (
823 EmpathyCellRendererActivatable
*cell
,
824 const gchar
*path_string
,
825 EmpathyContactListView
*view
)
827 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
830 EmpathyContact
*contact
;
831 EmpathyContactList
*list
;
833 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
834 if (!gtk_tree_model_get_iter_from_string (model
, &iter
, path_string
))
837 gtk_tree_model_get (model
, &iter
,
838 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
843 list
= empathy_contact_list_store_get_list_iface (priv
->store
);
844 if (empathy_contact_list_is_favourite (list
, contact
)) {
845 empathy_contact_list_remove_from_favourites (list
, contact
);
847 empathy_contact_list_add_to_favourites (list
, contact
);
850 g_object_unref (contact
);
852 #endif /* HAVE_FAVOURITE_CONTACTS */
855 contact_list_view_cell_set_background (EmpathyContactListView
*view
,
856 GtkCellRenderer
*cell
,
863 style
= gtk_widget_get_style (GTK_WIDGET (view
));
865 if (!is_group
&& is_active
) {
866 color
= style
->bg
[GTK_STATE_SELECTED
];
868 /* Here we take the current theme colour and add it to
869 * the colour for white and average the two. This
870 * gives a colour which is inline with the theme but
873 color
.red
= (color
.red
+ (style
->white
).red
) / 2;
874 color
.green
= (color
.green
+ (style
->white
).green
) / 2;
875 color
.blue
= (color
.blue
+ (style
->white
).blue
) / 2;
878 "cell-background-gdk", &color
,
882 "cell-background-gdk", NULL
,
888 contact_list_view_pixbuf_cell_data_func (GtkTreeViewColumn
*tree_column
,
889 GtkCellRenderer
*cell
,
892 EmpathyContactListView
*view
)
898 gtk_tree_model_get (model
, iter
,
899 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
900 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, &is_active
,
901 EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS
, &pixbuf
,
905 "visible", !is_group
,
909 if (pixbuf
!= NULL
) {
910 g_object_unref (pixbuf
);
913 contact_list_view_cell_set_background (view
, cell
, is_group
, is_active
);
917 contact_list_view_audio_call_cell_data_func (
918 GtkTreeViewColumn
*tree_column
,
919 GtkCellRenderer
*cell
,
922 EmpathyContactListView
*view
)
926 gboolean can_audio
, can_video
;
928 gtk_tree_model_get (model
, iter
,
929 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
930 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, &is_active
,
931 EMPATHY_CONTACT_LIST_STORE_COL_CAN_AUDIO_CALL
, &can_audio
,
932 EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL
, &can_video
,
936 "visible", !is_group
&& (can_audio
|| can_video
),
937 "icon-name", can_video
? EMPATHY_IMAGE_VIDEO_CALL
: EMPATHY_IMAGE_VOIP
,
940 contact_list_view_cell_set_background (view
, cell
, is_group
, is_active
);
944 contact_list_view_avatar_cell_data_func (GtkTreeViewColumn
*tree_column
,
945 GtkCellRenderer
*cell
,
948 EmpathyContactListView
*view
)
951 gboolean show_avatar
;
955 gtk_tree_model_get (model
, iter
,
956 EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR
, &pixbuf
,
957 EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE
, &show_avatar
,
958 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
959 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, &is_active
,
963 "visible", !is_group
&& show_avatar
,
968 g_object_unref (pixbuf
);
971 contact_list_view_cell_set_background (view
, cell
, is_group
, is_active
);
975 contact_list_view_text_cell_data_func (GtkTreeViewColumn
*tree_column
,
976 GtkCellRenderer
*cell
,
979 EmpathyContactListView
*view
)
983 gboolean show_status
;
986 gtk_tree_model_get (model
, iter
,
987 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
988 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, &is_active
,
989 EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE
, &show_status
,
990 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name
,
994 "show-status", show_status
,
999 contact_list_view_cell_set_background (view
, cell
, is_group
, is_active
);
1003 contact_list_view_expander_cell_data_func (GtkTreeViewColumn
*column
,
1004 GtkCellRenderer
*cell
,
1005 GtkTreeModel
*model
,
1007 EmpathyContactListView
*view
)
1012 gtk_tree_model_get (model
, iter
,
1013 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
1014 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, &is_active
,
1017 if (gtk_tree_model_iter_has_child (model
, iter
)) {
1019 gboolean row_expanded
;
1021 path
= gtk_tree_model_get_path (model
, iter
);
1022 row_expanded
= gtk_tree_view_row_expanded (GTK_TREE_VIEW (gtk_tree_view_column_get_tree_view (column
)), path
);
1023 gtk_tree_path_free (path
);
1027 "expander-style", row_expanded
? GTK_EXPANDER_EXPANDED
: GTK_EXPANDER_COLLAPSED
,
1030 g_object_set (cell
, "visible", FALSE
, NULL
);
1033 contact_list_view_cell_set_background (view
, cell
, is_group
, is_active
);
1036 #if HAVE_FAVOURITE_CONTACTS
1038 contact_list_view_favourite_cell_data_func (
1039 GtkTreeViewColumn
*tree_column
,
1040 GtkCellRenderer
*cell
,
1041 GtkTreeModel
*model
,
1043 EmpathyContactListView
*view
)
1047 gboolean is_separator
;
1048 gboolean is_favourite
;
1049 const gchar
*icon_name
= NULL
;
1051 gtk_tree_model_get (model
, iter
,
1052 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
1053 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, &is_active
,
1054 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, &is_separator
,
1055 EMPATHY_CONTACT_LIST_STORE_COL_IS_FAVOURITE
, &is_favourite
,
1058 if (!is_separator
&& !is_group
)
1059 icon_name
= (is_favourite
? EMPATHY_IMAGE_FAVOURITE
:
1060 EMPATHY_IMAGE_UNFAVOURITE
);
1063 "visible", (icon_name
!= NULL
),
1064 "icon-name", icon_name
,
1067 contact_list_view_cell_set_background (view
, cell
, is_group
, is_active
);
1069 #endif /* HAVE_FAVOURITE_CONTACTS */
1072 contact_list_view_row_expand_or_collapse_cb (EmpathyContactListView
*view
,
1077 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
1078 GtkTreeModel
*model
;
1082 if (!(priv
->list_features
& EMPATHY_CONTACT_LIST_FEATURE_GROUPS_SAVE
)) {
1086 model
= gtk_tree_view_get_model (GTK_TREE_VIEW (view
));
1088 gtk_tree_model_get (model
, iter
,
1089 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name
,
1092 expanded
= GPOINTER_TO_INT (user_data
);
1093 empathy_contact_group_set_expanded (name
, expanded
);
1099 contact_list_view_row_has_child_toggled_cb (GtkTreeModel
*model
,
1102 EmpathyContactListView
*view
)
1104 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
1105 gboolean is_group
= FALSE
;
1108 gtk_tree_model_get (model
, iter
,
1109 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
1110 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name
,
1113 if (!is_group
|| EMP_STR_EMPTY (name
)) {
1118 if (!(priv
->list_features
& EMPATHY_CONTACT_LIST_FEATURE_GROUPS_SAVE
) ||
1119 empathy_contact_group_get_expanded (name
)) {
1120 g_signal_handlers_block_by_func (view
,
1121 contact_list_view_row_expand_or_collapse_cb
,
1122 GINT_TO_POINTER (TRUE
));
1123 gtk_tree_view_expand_row (GTK_TREE_VIEW (view
), path
, TRUE
);
1124 g_signal_handlers_unblock_by_func (view
,
1125 contact_list_view_row_expand_or_collapse_cb
,
1126 GINT_TO_POINTER (TRUE
));
1128 g_signal_handlers_block_by_func (view
,
1129 contact_list_view_row_expand_or_collapse_cb
,
1130 GINT_TO_POINTER (FALSE
));
1131 gtk_tree_view_collapse_row (GTK_TREE_VIEW (view
), path
);
1132 g_signal_handlers_unblock_by_func (view
,
1133 contact_list_view_row_expand_or_collapse_cb
,
1134 GINT_TO_POINTER (FALSE
));
1141 contact_list_view_setup (EmpathyContactListView
*view
)
1143 EmpathyContactListViewPriv
*priv
;
1144 GtkCellRenderer
*cell
;
1145 GtkTreeViewColumn
*col
;
1148 priv
= GET_PRIV (view
);
1150 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view
),
1151 empathy_contact_list_store_search_equal_func
,
1154 g_signal_connect (priv
->store
, "row-has-child-toggled",
1155 G_CALLBACK (contact_list_view_row_has_child_toggled_cb
),
1157 gtk_tree_view_set_model (GTK_TREE_VIEW (view
),
1158 GTK_TREE_MODEL (priv
->store
));
1161 /* Setting reorderable is a hack that gets us row previews as drag icons
1162 for free. We override all the drag handlers. It's tricky to get the
1163 position of the drag icon right in drag_begin. GtkTreeView has special
1164 voodoo for it, so we let it do the voodoo that he do.
1167 "headers-visible", FALSE
,
1168 "reorderable", TRUE
,
1169 "show-expanders", FALSE
,
1172 col
= gtk_tree_view_column_new ();
1174 #if HAVE_FAVOURITE_CONTACTS
1175 /* Favourite Icon */
1176 cell
= empathy_cell_renderer_activatable_new ();
1177 gtk_tree_view_column_pack_start (col
, cell
, FALSE
);
1178 gtk_tree_view_column_set_cell_data_func (
1180 (GtkTreeCellDataFunc
) contact_list_view_favourite_cell_data_func
,
1187 g_signal_connect (cell
, "path-activated",
1188 G_CALLBACK (contact_list_view_favourite_toggled_cb
),
1193 cell
= gtk_cell_renderer_pixbuf_new ();
1194 gtk_tree_view_column_pack_start (col
, cell
, FALSE
);
1195 gtk_tree_view_column_set_cell_data_func (
1197 (GtkTreeCellDataFunc
) contact_list_view_pixbuf_cell_data_func
,
1207 cell
= empathy_cell_renderer_text_new ();
1208 gtk_tree_view_column_pack_start (col
, cell
, TRUE
);
1209 gtk_tree_view_column_set_cell_data_func (
1211 (GtkTreeCellDataFunc
) contact_list_view_text_cell_data_func
,
1214 gtk_tree_view_column_add_attribute (col
, cell
,
1215 "name", EMPATHY_CONTACT_LIST_STORE_COL_NAME
);
1216 gtk_tree_view_column_add_attribute (col
, cell
,
1217 "status", EMPATHY_CONTACT_LIST_STORE_COL_STATUS
);
1218 gtk_tree_view_column_add_attribute (col
, cell
,
1219 "is_group", EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
);
1221 /* Audio Call Icon */
1222 cell
= empathy_cell_renderer_activatable_new ();
1223 gtk_tree_view_column_pack_start (col
, cell
, FALSE
);
1224 gtk_tree_view_column_set_cell_data_func (
1226 (GtkTreeCellDataFunc
) contact_list_view_audio_call_cell_data_func
,
1233 g_signal_connect (cell
, "path-activated",
1234 G_CALLBACK (contact_list_view_call_activated_cb
),
1238 cell
= gtk_cell_renderer_pixbuf_new ();
1239 gtk_tree_view_column_pack_start (col
, cell
, FALSE
);
1240 gtk_tree_view_column_set_cell_data_func (
1242 (GtkTreeCellDataFunc
) contact_list_view_avatar_cell_data_func
,
1254 cell
= empathy_cell_renderer_expander_new ();
1255 gtk_tree_view_column_pack_end (col
, cell
, FALSE
);
1256 gtk_tree_view_column_set_cell_data_func (
1258 (GtkTreeCellDataFunc
) contact_list_view_expander_cell_data_func
,
1261 /* Actually add the column now we have added all cell renderers */
1262 gtk_tree_view_append_column (GTK_TREE_VIEW (view
), col
);
1265 for (i
= 0; i
< G_N_ELEMENTS (drag_types_dest
); ++i
) {
1266 drag_atoms_dest
[i
] = gdk_atom_intern (drag_types_dest
[i
].target
,
1270 for (i
= 0; i
< G_N_ELEMENTS (drag_types_source
); ++i
) {
1271 drag_atoms_source
[i
] = gdk_atom_intern (drag_types_source
[i
].target
,
1277 contact_list_view_set_list_features (EmpathyContactListView
*view
,
1278 EmpathyContactListFeatureFlags features
)
1280 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
1281 gboolean has_tooltip
;
1283 g_return_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view
));
1285 priv
->list_features
= features
;
1287 /* Update DnD source/dest */
1288 if (features
& EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DRAG
) {
1289 gtk_drag_source_set (GTK_WIDGET (view
),
1292 G_N_ELEMENTS (drag_types_source
),
1293 GDK_ACTION_MOVE
| GDK_ACTION_COPY
);
1295 gtk_drag_source_unset (GTK_WIDGET (view
));
1299 if (features
& EMPATHY_CONTACT_LIST_FEATURE_CONTACT_DROP
) {
1300 gtk_drag_dest_set (GTK_WIDGET (view
),
1301 GTK_DEST_DEFAULT_ALL
,
1303 G_N_ELEMENTS (drag_types_dest
),
1304 GDK_ACTION_MOVE
| GDK_ACTION_COPY
);
1306 /* FIXME: URI could still be droped depending on FT feature */
1307 gtk_drag_dest_unset (GTK_WIDGET (view
));
1310 /* Update has-tooltip */
1311 has_tooltip
= (features
& EMPATHY_CONTACT_LIST_FEATURE_CONTACT_TOOLTIP
) != 0;
1312 gtk_widget_set_has_tooltip (GTK_WIDGET (view
), has_tooltip
);
1316 contact_list_view_finalize (GObject
*object
)
1318 EmpathyContactListViewPriv
*priv
;
1320 priv
= GET_PRIV (object
);
1323 g_object_unref (priv
->store
);
1325 if (priv
->tooltip_widget
) {
1326 gtk_widget_destroy (priv
->tooltip_widget
);
1328 if (priv
->file_targets
) {
1329 gtk_target_list_unref (priv
->file_targets
);
1332 G_OBJECT_CLASS (empathy_contact_list_view_parent_class
)->finalize (object
);
1336 contact_list_view_get_property (GObject
*object
,
1341 EmpathyContactListViewPriv
*priv
;
1343 priv
= GET_PRIV (object
);
1347 g_value_set_object (value
, priv
->store
);
1349 case PROP_LIST_FEATURES
:
1350 g_value_set_flags (value
, priv
->list_features
);
1352 case PROP_CONTACT_FEATURES
:
1353 g_value_set_flags (value
, priv
->contact_features
);
1356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
1362 contact_list_view_set_property (GObject
*object
,
1364 const GValue
*value
,
1367 EmpathyContactListView
*view
= EMPATHY_CONTACT_LIST_VIEW (object
);
1368 EmpathyContactListViewPriv
*priv
= GET_PRIV (object
);
1372 priv
->store
= g_value_dup_object (value
);
1373 contact_list_view_setup (view
);
1375 case PROP_LIST_FEATURES
:
1376 contact_list_view_set_list_features (view
, g_value_get_flags (value
));
1378 case PROP_CONTACT_FEATURES
:
1379 priv
->contact_features
= g_value_get_flags (value
);
1382 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
1388 empathy_contact_list_view_class_init (EmpathyContactListViewClass
*klass
)
1390 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1391 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS (klass
);
1392 GtkTreeViewClass
*tree_view_class
= GTK_TREE_VIEW_CLASS (klass
);
1394 object_class
->finalize
= contact_list_view_finalize
;
1395 object_class
->get_property
= contact_list_view_get_property
;
1396 object_class
->set_property
= contact_list_view_set_property
;
1398 widget_class
->drag_data_received
= contact_list_view_drag_data_received
;
1399 widget_class
->drag_drop
= contact_list_view_drag_drop
;
1400 widget_class
->drag_begin
= contact_list_view_drag_begin
;
1401 widget_class
->drag_data_get
= contact_list_view_drag_data_get
;
1402 widget_class
->drag_end
= contact_list_view_drag_end
;
1403 widget_class
->drag_motion
= contact_list_view_drag_motion
;
1405 /* We use the class method to let user of this widget to connect to
1406 * the signal and stop emission of the signal so the default handler
1407 * won't be called. */
1408 tree_view_class
->row_activated
= contact_list_view_row_activated
;
1410 signals
[DRAG_CONTACT_RECEIVED
] =
1411 g_signal_new ("drag-contact-received",
1412 G_OBJECT_CLASS_TYPE (klass
),
1416 _empathy_gtk_marshal_VOID__OBJECT_STRING_STRING
,
1418 3, EMPATHY_TYPE_CONTACT
, G_TYPE_STRING
, G_TYPE_STRING
);
1420 g_object_class_install_property (object_class
,
1422 g_param_spec_object ("store",
1423 "The store of the view",
1424 "The store of the view",
1425 EMPATHY_TYPE_CONTACT_LIST_STORE
,
1426 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
1427 g_object_class_install_property (object_class
,
1429 g_param_spec_flags ("list-features",
1430 "Features of the view",
1431 "Falgs for all enabled features",
1432 EMPATHY_TYPE_CONTACT_LIST_FEATURE_FLAGS
,
1433 EMPATHY_CONTACT_LIST_FEATURE_NONE
,
1434 G_PARAM_READWRITE
));
1435 g_object_class_install_property (object_class
,
1436 PROP_CONTACT_FEATURES
,
1437 g_param_spec_flags ("contact-features",
1438 "Features of the contact menu",
1439 "Falgs for all enabled features for the menu",
1440 EMPATHY_TYPE_CONTACT_FEATURE_FLAGS
,
1441 EMPATHY_CONTACT_FEATURE_NONE
,
1442 G_PARAM_READWRITE
));
1444 g_type_class_add_private (object_class
, sizeof (EmpathyContactListViewPriv
));
1448 empathy_contact_list_view_init (EmpathyContactListView
*view
)
1450 EmpathyContactListViewPriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (view
,
1451 EMPATHY_TYPE_CONTACT_LIST_VIEW
, EmpathyContactListViewPriv
);
1454 /* Get saved group states. */
1455 empathy_contact_groups_get_all ();
1457 gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (view
),
1458 empathy_contact_list_store_row_separator_func
,
1461 /* Set up drag target lists. */
1462 priv
->file_targets
= gtk_target_list_new (drag_types_dest_file
,
1463 G_N_ELEMENTS (drag_types_dest_file
));
1465 /* Connect to tree view signals rather than override. */
1466 g_signal_connect (view
, "button-press-event",
1467 G_CALLBACK (contact_list_view_button_press_event_cb
),
1469 g_signal_connect (view
, "key-press-event",
1470 G_CALLBACK (contact_list_view_key_press_event_cb
),
1472 g_signal_connect (view
, "row-expanded",
1473 G_CALLBACK (contact_list_view_row_expand_or_collapse_cb
),
1474 GINT_TO_POINTER (TRUE
));
1475 g_signal_connect (view
, "row-collapsed",
1476 G_CALLBACK (contact_list_view_row_expand_or_collapse_cb
),
1477 GINT_TO_POINTER (FALSE
));
1478 g_signal_connect (view
, "query-tooltip",
1479 G_CALLBACK (contact_list_view_query_tooltip_cb
),
1483 EmpathyContactListView
*
1484 empathy_contact_list_view_new (EmpathyContactListStore
*store
,
1485 EmpathyContactListFeatureFlags list_features
,
1486 EmpathyContactFeatureFlags contact_features
)
1488 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), NULL
);
1490 return g_object_new (EMPATHY_TYPE_CONTACT_LIST_VIEW
,
1492 "contact-features", contact_features
,
1493 "list-features", list_features
,
1498 empathy_contact_list_view_dup_selected (EmpathyContactListView
*view
)
1500 EmpathyContactListViewPriv
*priv
;
1501 GtkTreeSelection
*selection
;
1503 GtkTreeModel
*model
;
1504 EmpathyContact
*contact
;
1506 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view
), NULL
);
1508 priv
= GET_PRIV (view
);
1510 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
1511 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
1515 gtk_tree_model_get (model
, &iter
,
1516 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
1522 EmpathyContactListFlags
1523 empathy_contact_list_view_get_flags (EmpathyContactListView
*view
)
1525 EmpathyContactListViewPriv
*priv
;
1526 GtkTreeSelection
*selection
;
1528 GtkTreeModel
*model
;
1529 EmpathyContactListFlags flags
;
1531 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view
), 0);
1533 priv
= GET_PRIV (view
);
1535 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
1536 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
1540 gtk_tree_model_get (model
, &iter
,
1541 EMPATHY_CONTACT_LIST_STORE_COL_FLAGS
, &flags
,
1548 empathy_contact_list_view_get_selected_group (EmpathyContactListView
*view
)
1550 EmpathyContactListViewPriv
*priv
;
1551 GtkTreeSelection
*selection
;
1553 GtkTreeModel
*model
;
1557 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view
), NULL
);
1559 priv
= GET_PRIV (view
);
1561 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (view
));
1562 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
1566 gtk_tree_model_get (model
, &iter
,
1567 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
1568 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name
,
1580 contact_list_view_remove_dialog_show (GtkWindow
*parent
,
1581 const gchar
*message
,
1582 const gchar
*secondary_text
)
1587 dialog
= gtk_message_dialog_new (parent
, GTK_DIALOG_MODAL
,
1588 GTK_MESSAGE_QUESTION
, GTK_BUTTONS_NONE
,
1590 gtk_dialog_add_buttons (GTK_DIALOG (dialog
),
1591 GTK_STOCK_CANCEL
, GTK_RESPONSE_NO
,
1592 GTK_STOCK_DELETE
, GTK_RESPONSE_YES
,
1594 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog
),
1595 "%s", secondary_text
);
1597 gtk_widget_show (dialog
);
1599 res
= gtk_dialog_run (GTK_DIALOG (dialog
));
1600 gtk_widget_destroy (dialog
);
1602 return (res
== GTK_RESPONSE_YES
);
1606 contact_list_view_group_remove_activate_cb (GtkMenuItem
*menuitem
,
1607 EmpathyContactListView
*view
)
1609 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
1612 group
= empathy_contact_list_view_get_selected_group (view
);
1617 text
= g_strdup_printf (_("Do you really want to remove the group '%s'?"), group
);
1618 parent
= empathy_get_toplevel_window (GTK_WIDGET (view
));
1619 if (contact_list_view_remove_dialog_show (parent
, _("Removing group"), text
)) {
1620 EmpathyContactList
*list
;
1622 list
= empathy_contact_list_store_get_list_iface (priv
->store
);
1623 empathy_contact_list_remove_group (list
, group
);
1633 empathy_contact_list_view_get_group_menu (EmpathyContactListView
*view
)
1635 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
1641 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view
), NULL
);
1643 if (!(priv
->list_features
& (EMPATHY_CONTACT_LIST_FEATURE_GROUPS_RENAME
|
1644 EMPATHY_CONTACT_LIST_FEATURE_GROUPS_REMOVE
))) {
1648 group
= empathy_contact_list_view_get_selected_group (view
);
1653 menu
= gtk_menu_new ();
1655 /* FIXME: Not implemented yet
1656 if (priv->features & EMPATHY_CONTACT_LIST_FEATURE_GROUPS_RENAME) {
1657 item = gtk_menu_item_new_with_mnemonic (_("Re_name"));
1658 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1659 gtk_widget_show (item);
1660 g_signal_connect (item, "activate",
1661 G_CALLBACK (contact_list_view_group_rename_activate_cb),
1665 if (priv
->list_features
& EMPATHY_CONTACT_LIST_FEATURE_GROUPS_REMOVE
) {
1666 item
= gtk_image_menu_item_new_with_mnemonic (_("_Remove"));
1667 image
= gtk_image_new_from_icon_name (GTK_STOCK_REMOVE
,
1668 GTK_ICON_SIZE_MENU
);
1669 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item
), image
);
1670 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1671 gtk_widget_show (item
);
1672 g_signal_connect (item
, "activate",
1673 G_CALLBACK (contact_list_view_group_remove_activate_cb
),
1683 contact_list_view_remove_activate_cb (GtkMenuItem
*menuitem
,
1684 EmpathyContactListView
*view
)
1686 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
1687 EmpathyContact
*contact
;
1689 contact
= empathy_contact_list_view_dup_selected (view
);
1695 parent
= empathy_get_toplevel_window (GTK_WIDGET (view
));
1696 text
= g_strdup_printf (_("Do you really want to remove the contact '%s'?"),
1697 empathy_contact_get_name (contact
));
1698 if (contact_list_view_remove_dialog_show (parent
, _("Removing contact"), text
)) {
1699 EmpathyContactList
*list
;
1701 list
= empathy_contact_list_store_get_list_iface (priv
->store
);
1702 empathy_contact_list_remove (list
, contact
, "");
1706 g_object_unref (contact
);
1711 empathy_contact_list_view_get_contact_menu (EmpathyContactListView
*view
)
1713 EmpathyContactListViewPriv
*priv
= GET_PRIV (view
);
1714 EmpathyContact
*contact
;
1718 EmpathyContactListFlags flags
;
1720 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_VIEW (view
), NULL
);
1722 contact
= empathy_contact_list_view_dup_selected (view
);
1726 flags
= empathy_contact_list_view_get_flags (view
);
1728 menu
= empathy_contact_menu_new (contact
, priv
->contact_features
);
1730 /* Remove contact */
1731 if (priv
->list_features
& EMPATHY_CONTACT_LIST_FEATURE_CONTACT_REMOVE
&&
1732 flags
& EMPATHY_CONTACT_LIST_CAN_REMOVE
) {
1733 /* create the menu if required, or just add a separator */
1735 menu
= gtk_menu_new ();
1737 item
= gtk_separator_menu_item_new ();
1738 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1739 gtk_widget_show (item
);
1743 item
= gtk_image_menu_item_new_with_mnemonic (_("_Remove"));
1744 image
= gtk_image_new_from_icon_name (GTK_STOCK_REMOVE
,
1745 GTK_ICON_SIZE_MENU
);
1746 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item
), image
);
1747 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), item
);
1748 gtk_widget_show (item
);
1749 g_signal_connect (item
, "activate",
1750 G_CALLBACK (contact_list_view_remove_activate_cb
),
1754 g_object_unref (contact
);