1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2008-2010 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
20 * Travis Reitter <travis.reitter@collabora.co.uk>
27 #include <glib/gi18n-lib.h>
29 #include <telepathy-glib/util.h>
31 #include <folks/folks.h>
32 #include <folks/folks-telepathy.h>
34 #include <libempathy/empathy-request-util.h>
35 #include <libempathy/empathy-individual-manager.h>
36 #include <libempathy/empathy-chatroom-manager.h>
37 #include <libempathy/empathy-utils.h>
39 #include "empathy-individual-menu.h"
40 #include "empathy-images.h"
41 #include "empathy-log-window.h"
42 #include "empathy-contact-dialogs.h"
43 #include "empathy-gtk-enum-types.h"
44 #include "empathy-individual-edit-dialog.h"
45 #include "empathy-individual-information-dialog.h"
46 #include "empathy-ui-utils.h"
47 #include "empathy-share-my-desktop.h"
48 #include "empathy-linking-dialog.h"
49 #include "empathy-call-utils.h"
51 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualMenu)
54 FolksIndividual *individual; /* owned */
55 EmpathyIndividualFeatureFlags features;
56 } EmpathyIndividualMenuPriv;
64 SIGNAL_LINK_CONTACTS_ACTIVATED,
68 static guint signals[LAST_SIGNAL];
70 G_DEFINE_TYPE (EmpathyIndividualMenu, empathy_individual_menu, GTK_TYPE_MENU);
73 individual_menu_add_personas (GtkMenuShell *menu,
74 FolksIndividual *individual,
75 EmpathyIndividualFeatureFlags features)
80 guint persona_count = 0;
83 g_return_if_fail (GTK_IS_MENU (menu));
84 g_return_if_fail (FOLKS_IS_INDIVIDUAL (individual));
85 g_return_if_fail (empathy_folks_individual_contains_contact (individual));
87 personas = folks_individual_get_personas (individual);
88 /* we'll re-use this iterator throughout */
89 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
91 /* Make sure we've got enough valid entries for these menu items to add
93 while (gee_iterator_next (iter))
95 FolksPersona *persona = gee_iterator_get (iter);
96 if (empathy_folks_persona_is_interesting (persona))
99 g_clear_object (&persona);
102 /* return early if these entries would add nothing beyond the "quick" items */
103 if (persona_count <= 1)
106 /* add a separator before the list of personas */
107 item = gtk_separator_menu_item_new ();
108 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
109 gtk_widget_show (item);
111 personas = folks_individual_get_personas (individual);
112 for (c = gee_iterator_first (iter); c; c = gee_iterator_next (iter))
115 GtkWidget *contact_item;
116 GtkWidget *contact_submenu;
117 TpContact *tp_contact;
118 EmpathyContact *contact;
119 TpfPersona *persona = gee_iterator_get (iter);
121 FolksPersonaStore *store;
122 const gchar *account;
125 if (!empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
128 tp_contact = tpf_persona_get_contact (persona);
129 contact = empathy_contact_dup_from_tp_contact (tp_contact);
131 store = folks_persona_get_store (FOLKS_PERSONA (persona));
132 account = folks_persona_store_get_display_name (store);
134 /* Translators: this is used in the context menu for a contact. The first
135 * parameter is a contact ID (e.g. foo@jabber.org) and the second is one
136 * of the user's account IDs (e.g. me@hotmail.com). */
137 label = g_strdup_printf (_("%s (%s)"),
138 folks_persona_get_display_id (FOLKS_PERSONA (persona)), account);
140 contact_item = gtk_image_menu_item_new_with_label (label);
141 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (contact_item),
143 contact_submenu = gtk_menu_new ();
144 gtk_menu_item_set_submenu (GTK_MENU_ITEM (contact_item), contact_submenu);
145 image = gtk_image_new_from_icon_name (
146 empathy_icon_name_for_contact (contact), GTK_ICON_SIZE_MENU);
147 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (contact_item), image);
148 gtk_widget_show (image);
151 if (features & EMPATHY_INDIVIDUAL_FEATURE_CHAT)
153 action = empathy_individual_chat_menu_item_new (NULL, contact);
154 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
155 gtk_widget_show (action);
159 if (features & EMPATHY_INDIVIDUAL_FEATURE_SMS)
161 action = empathy_individual_sms_menu_item_new (NULL, contact);
162 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
163 gtk_widget_show (action);
166 if (features & EMPATHY_INDIVIDUAL_FEATURE_CALL)
169 action = empathy_individual_audio_call_menu_item_new (NULL, contact);
170 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
171 gtk_widget_show (action);
174 action = empathy_individual_video_call_menu_item_new (NULL, contact);
175 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
176 gtk_widget_show (action);
180 if (features & EMPATHY_INDIVIDUAL_FEATURE_LOG)
182 action = empathy_individual_log_menu_item_new (NULL, contact);
183 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
184 gtk_widget_show (action);
188 action = empathy_individual_invite_menu_item_new (NULL, contact);
189 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
190 gtk_widget_show (action);
193 action = empathy_individual_file_transfer_menu_item_new (NULL, contact);
194 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
195 gtk_widget_show (action);
197 /* Share my desktop */
198 action = empathy_individual_share_my_desktop_menu_item_new (NULL,
200 gtk_menu_shell_append (GTK_MENU_SHELL (contact_submenu), action);
201 gtk_widget_show (action);
203 gtk_menu_shell_append (GTK_MENU_SHELL (menu), contact_item);
204 gtk_widget_show (contact_item);
207 g_object_unref (contact);
210 g_clear_object (&persona);
213 g_clear_object (&iter);
217 individual_link_menu_item_activate_cb (EmpathyIndividualMenu *self)
219 EmpathyIndividualMenuPriv *priv = GET_PRIV (self);
222 dialog = empathy_linking_dialog_show (priv->individual, NULL);
223 g_signal_emit (self, signals[SIGNAL_LINK_CONTACTS_ACTIVATED], 0, dialog);
227 empathy_individual_menu_init (EmpathyIndividualMenu *self)
229 EmpathyIndividualMenuPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
230 EMPATHY_TYPE_INDIVIDUAL_MENU, EmpathyIndividualMenuPriv);
236 constructed (GObject *object)
238 EmpathyIndividualMenuPriv *priv = GET_PRIV (object);
241 FolksIndividual *individual;
242 EmpathyIndividualFeatureFlags features;
245 shell = GTK_MENU_SHELL (object);
246 individual = priv->individual;
247 features = priv->features;
250 if (features & EMPATHY_INDIVIDUAL_FEATURE_CHAT)
252 item = empathy_individual_chat_menu_item_new (individual, NULL);
255 gtk_menu_shell_append (shell, item);
256 gtk_widget_show (item);
261 if (features & EMPATHY_INDIVIDUAL_FEATURE_SMS)
263 item = empathy_individual_sms_menu_item_new (individual, NULL);
266 gtk_menu_shell_append (shell, item);
267 gtk_widget_show (item);
271 if (features & EMPATHY_INDIVIDUAL_FEATURE_CALL)
274 item = empathy_individual_audio_call_menu_item_new (individual, NULL);
275 gtk_menu_shell_append (shell, item);
276 gtk_widget_show (item);
279 item = empathy_individual_video_call_menu_item_new (individual, NULL);
280 gtk_menu_shell_append (shell, item);
281 gtk_widget_show (item);
285 if (features & EMPATHY_INDIVIDUAL_FEATURE_LOG)
287 item = empathy_individual_log_menu_item_new (individual, NULL);
288 gtk_menu_shell_append (shell, item);
289 gtk_widget_show (item);
293 item = empathy_individual_invite_menu_item_new (individual, NULL);
294 gtk_menu_shell_append (shell, item);
295 gtk_widget_show (item);
298 item = empathy_individual_file_transfer_menu_item_new (individual, NULL);
299 gtk_menu_shell_append (shell, item);
300 gtk_widget_show (item);
302 /* Share my desktop */
303 /* FIXME we should add the "Share my desktop" menu item if Vino is
304 a registered handler in MC5 */
305 item = empathy_individual_share_my_desktop_menu_item_new (individual, NULL);
306 gtk_menu_shell_append (shell, item);
307 gtk_widget_show (item);
309 /* Menu items to target specific contacts */
310 individual_menu_add_personas (GTK_MENU_SHELL (object), individual, features);
313 if (features & (EMPATHY_INDIVIDUAL_FEATURE_EDIT |
314 EMPATHY_INDIVIDUAL_FEATURE_INFO |
315 EMPATHY_INDIVIDUAL_FEATURE_FAVOURITE |
316 EMPATHY_INDIVIDUAL_FEATURE_LINK))
318 item = gtk_separator_menu_item_new ();
319 gtk_menu_shell_append (shell, item);
320 gtk_widget_show (item);
324 if (features & EMPATHY_INDIVIDUAL_FEATURE_EDIT)
326 item = empathy_individual_edit_menu_item_new (individual);
327 gtk_menu_shell_append (shell, item);
328 gtk_widget_show (item);
332 if (features & EMPATHY_INDIVIDUAL_FEATURE_LINK)
334 item = empathy_individual_link_menu_item_new (individual);
335 gtk_menu_shell_append (shell, item);
337 g_signal_connect_swapped (item, "activate",
338 (GCallback) individual_link_menu_item_activate_cb, object);
340 gtk_widget_show (item);
344 if (features & EMPATHY_INDIVIDUAL_FEATURE_INFO)
346 item = empathy_individual_info_menu_item_new (individual);
347 gtk_menu_shell_append (shell, item);
348 gtk_widget_show (item);
351 /* Favorite checkbox */
352 if (features & EMPATHY_INDIVIDUAL_FEATURE_FAVOURITE)
354 item = empathy_individual_favourite_menu_item_new (individual);
355 gtk_menu_shell_append (shell, item);
356 gtk_widget_show (item);
361 get_property (GObject *object,
366 EmpathyIndividualMenuPriv *priv;
368 priv = GET_PRIV (object);
372 case PROP_INDIVIDUAL:
373 g_value_set_object (value, priv->individual);
376 g_value_set_flags (value, priv->features);
379 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
385 set_property (GObject *object,
390 EmpathyIndividualMenuPriv *priv;
392 priv = GET_PRIV (object);
396 case PROP_INDIVIDUAL:
397 priv->individual = g_value_dup_object (value);
400 priv->features = g_value_get_flags (value);
403 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
409 dispose (GObject *object)
411 EmpathyIndividualMenuPriv *priv = GET_PRIV (object);
413 tp_clear_object (&priv->individual);
415 G_OBJECT_CLASS (empathy_individual_menu_parent_class)->dispose (object);
419 empathy_individual_menu_class_init (EmpathyIndividualMenuClass *klass)
421 GObjectClass *object_class = G_OBJECT_CLASS (klass);
423 object_class->constructed = constructed;
424 object_class->get_property = get_property;
425 object_class->set_property = set_property;
426 object_class->dispose = dispose;
429 * EmpathyIndividualMenu:individual:
431 * The #FolksIndividual the menu is for.
433 g_object_class_install_property (object_class, PROP_INDIVIDUAL,
434 g_param_spec_object ("individual",
436 "The #FolksIndividual the menu is for.",
437 FOLKS_TYPE_INDIVIDUAL,
438 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
441 * EmpathyIndividualMenu:features:
443 * A set of feature flags controlling which entries are shown.
445 g_object_class_install_property (object_class, PROP_FEATURES,
446 g_param_spec_flags ("features",
448 "A set of feature flags controlling which entries are shown.",
449 EMPATHY_TYPE_INDIVIDUAL_FEATURE_FLAGS,
450 EMPATHY_INDIVIDUAL_FEATURE_NONE,
451 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
453 signals[SIGNAL_LINK_CONTACTS_ACTIVATED] =
454 g_signal_new ("link-contacts-activated", G_OBJECT_CLASS_TYPE (klass),
455 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
456 g_cclosure_marshal_VOID__OBJECT,
457 G_TYPE_NONE, 1, EMPATHY_TYPE_LINKING_DIALOG);
459 g_type_class_add_private (object_class, sizeof (EmpathyIndividualMenuPriv));
463 empathy_individual_menu_new (FolksIndividual *individual,
464 EmpathyIndividualFeatureFlags features)
466 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
467 g_return_val_if_fail (features != EMPATHY_INDIVIDUAL_FEATURE_NONE, NULL);
469 return g_object_new (EMPATHY_TYPE_INDIVIDUAL_MENU,
470 "individual", individual,
471 "features", features,
475 /* Like menu_item_set_first_contact(), but always operates upon the given
476 * contact. If the contact is non-NULL, it is assumed that the menu entry should
479 menu_item_set_contact (GtkWidget *item,
480 EmpathyContact *contact,
481 GCallback activate_callback,
482 EmpathyActionType action_type)
484 gboolean can_do_action = FALSE;
487 can_do_action = empathy_contact_can_do_action (contact, action_type);
488 gtk_widget_set_sensitive (item, can_do_action);
490 if (can_do_action == TRUE)
492 /* We want to make sure that the EmpathyContact stays alive while the
493 * signal is connected. */
494 g_signal_connect_data (item, "activate", G_CALLBACK (activate_callback),
495 g_object_ref (contact), (GClosureNotify) g_object_unref, 0);
498 return can_do_action;
502 * Set the given menu @item to call @activate_callback using the TpContact
503 * (associated with @individual) with the highest availability who is also valid
504 * whenever @item is activated.
506 * @action_type is the type of action performed by the menu entry; this is used
507 * so that only contacts which can perform that action (e.g. are capable of
508 * receiving video calls) are selected, as appropriate.
511 menu_item_set_first_contact (GtkWidget *item,
512 FolksIndividual *individual,
513 GCallback activate_callback,
514 EmpathyActionType action_type)
516 EmpathyContact *best_contact;
518 best_contact = empathy_contact_dup_best_for_action (individual, action_type);
519 menu_item_set_contact (item, best_contact, G_CALLBACK (activate_callback),
521 tp_clear_object (&best_contact);
527 empathy_individual_chat_menu_item_activated (GtkMenuItem *item,
528 EmpathyContact *contact)
530 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
532 empathy_chat_with_contact (contact, empathy_get_current_action_time ());
536 empathy_individual_chat_menu_item_new (FolksIndividual *individual,
537 EmpathyContact *contact)
542 g_return_val_if_fail ((FOLKS_IS_INDIVIDUAL (individual) &&
543 empathy_folks_individual_contains_contact (individual)) ||
544 EMPATHY_IS_CONTACT (contact),
547 item = gtk_image_menu_item_new_with_mnemonic (_("_Chat"));
548 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_MESSAGE,
550 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
551 gtk_widget_show (image);
555 menu_item_set_contact (item, contact,
556 G_CALLBACK (empathy_individual_chat_menu_item_activated),
557 EMPATHY_ACTION_CHAT);
561 menu_item_set_first_contact (item, individual,
562 G_CALLBACK (empathy_individual_chat_menu_item_activated),
563 EMPATHY_ACTION_CHAT);
570 empathy_individual_sms_menu_item_activated (GtkMenuItem *item,
571 EmpathyContact *contact)
573 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
575 empathy_sms_contact_id (
576 empathy_contact_get_account (contact),
577 empathy_contact_get_id (contact),
578 empathy_get_current_action_time ());
582 empathy_individual_sms_menu_item_new (FolksIndividual *individual,
583 EmpathyContact *contact)
588 g_return_val_if_fail ((FOLKS_IS_INDIVIDUAL (individual) &&
589 empathy_folks_individual_contains_contact (individual)) ||
590 EMPATHY_IS_CONTACT (contact),
593 item = gtk_image_menu_item_new_with_mnemonic (_("_SMS"));
594 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_SMS,
596 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
597 gtk_widget_show (image);
601 menu_item_set_contact (item, contact,
602 G_CALLBACK (empathy_individual_sms_menu_item_activated),
607 menu_item_set_first_contact (item, individual,
608 G_CALLBACK (empathy_individual_sms_menu_item_activated),
616 empathy_individual_audio_call_menu_item_activated (GtkMenuItem *item,
617 EmpathyContact *contact)
619 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
621 empathy_call_new_with_streams (contact, TRUE, FALSE,
622 empathy_get_current_action_time ());
626 empathy_individual_audio_call_menu_item_new (FolksIndividual *individual,
627 EmpathyContact *contact)
632 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
633 EMPATHY_IS_CONTACT (contact),
636 item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Audio Call"));
637 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VOIP, GTK_ICON_SIZE_MENU);
638 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
639 gtk_widget_show (image);
643 menu_item_set_contact (item, contact,
644 G_CALLBACK (empathy_individual_audio_call_menu_item_activated),
645 EMPATHY_ACTION_AUDIO_CALL);
649 menu_item_set_first_contact (item, individual,
650 G_CALLBACK (empathy_individual_audio_call_menu_item_activated),
651 EMPATHY_ACTION_AUDIO_CALL);
658 empathy_individual_video_call_menu_item_activated (GtkMenuItem *item,
659 EmpathyContact *contact)
661 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
663 empathy_call_new_with_streams (contact, TRUE, TRUE,
664 empathy_get_current_action_time ());
668 empathy_individual_video_call_menu_item_new (FolksIndividual *individual,
669 EmpathyContact *contact)
674 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
675 EMPATHY_IS_CONTACT (contact),
678 item = gtk_image_menu_item_new_with_mnemonic (C_("menu item", "_Video Call"));
679 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VIDEO_CALL,
681 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
682 gtk_widget_show (image);
686 menu_item_set_contact (item, contact,
687 G_CALLBACK (empathy_individual_video_call_menu_item_activated),
688 EMPATHY_ACTION_VIDEO_CALL);
692 menu_item_set_first_contact (item, individual,
693 G_CALLBACK (empathy_individual_video_call_menu_item_activated),
694 EMPATHY_ACTION_VIDEO_CALL);
701 empathy_individual_log_menu_item_activated (GtkMenuItem *item,
702 EmpathyContact *contact)
704 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
706 empathy_log_window_show (empathy_contact_get_account (contact),
707 empathy_contact_get_id (contact), FALSE, NULL);
711 empathy_individual_log_menu_item_new (FolksIndividual *individual,
712 EmpathyContact *contact)
717 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
718 EMPATHY_IS_CONTACT (contact),
721 item = gtk_image_menu_item_new_with_mnemonic (_("_Previous Conversations"));
722 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_LOG, GTK_ICON_SIZE_MENU);
723 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
724 gtk_widget_show (image);
728 menu_item_set_contact (item, contact,
729 G_CALLBACK (empathy_individual_log_menu_item_activated),
730 EMPATHY_ACTION_VIEW_LOGS);
734 menu_item_set_first_contact (item, individual,
735 G_CALLBACK (empathy_individual_log_menu_item_activated),
736 EMPATHY_ACTION_VIEW_LOGS);
743 empathy_individual_file_transfer_menu_item_activated (GtkMenuItem *item,
744 EmpathyContact *contact)
746 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
748 empathy_send_file_with_file_chooser (contact);
752 empathy_individual_file_transfer_menu_item_new (FolksIndividual *individual,
753 EmpathyContact *contact)
758 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
759 EMPATHY_IS_CONTACT (contact),
762 item = gtk_image_menu_item_new_with_mnemonic (_("Send File"));
763 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_DOCUMENT_SEND,
765 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
766 gtk_widget_show (image);
770 menu_item_set_contact (item, contact,
771 G_CALLBACK (empathy_individual_file_transfer_menu_item_activated),
772 EMPATHY_ACTION_SEND_FILE);
776 menu_item_set_first_contact (item, individual,
777 G_CALLBACK (empathy_individual_file_transfer_menu_item_activated),
778 EMPATHY_ACTION_SEND_FILE);
785 empathy_individual_share_my_desktop_menu_item_activated (GtkMenuItem *item,
786 EmpathyContact *contact)
788 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
790 empathy_share_my_desktop_share_with_contact (contact);
794 empathy_individual_share_my_desktop_menu_item_new (FolksIndividual *individual,
795 EmpathyContact *contact)
800 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
801 EMPATHY_IS_CONTACT (contact),
804 item = gtk_image_menu_item_new_with_mnemonic (_("Share My Desktop"));
805 image = gtk_image_new_from_icon_name (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU);
806 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
807 gtk_widget_show (image);
811 menu_item_set_contact (item, contact,
812 G_CALLBACK (empathy_individual_share_my_desktop_menu_item_activated),
813 EMPATHY_ACTION_SHARE_MY_DESKTOP);
817 menu_item_set_first_contact (item, individual,
818 G_CALLBACK (empathy_individual_share_my_desktop_menu_item_activated),
819 EMPATHY_ACTION_SHARE_MY_DESKTOP);
826 favourite_menu_item_toggled_cb (GtkCheckMenuItem *item,
827 FolksIndividual *individual)
829 folks_favourite_details_set_is_favourite (
830 FOLKS_FAVOURITE_DETAILS (individual),
831 gtk_check_menu_item_get_active (item));
835 empathy_individual_favourite_menu_item_new (FolksIndividual *individual)
839 item = gtk_check_menu_item_new_with_label (_("Favorite"));
841 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
842 folks_favourite_details_get_is_favourite (
843 FOLKS_FAVOURITE_DETAILS (individual)));
845 g_signal_connect (item, "toggled",
846 G_CALLBACK (favourite_menu_item_toggled_cb), individual);
852 individual_info_menu_item_activate_cb (FolksIndividual *individual)
854 empathy_individual_information_dialog_show (individual, NULL);
858 empathy_individual_info_menu_item_new (FolksIndividual *individual)
863 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
864 g_return_val_if_fail (empathy_folks_individual_contains_contact (individual),
867 item = gtk_image_menu_item_new_with_mnemonic (_("Infor_mation"));
868 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_CONTACT_INFORMATION,
870 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
871 gtk_widget_show (image);
873 g_signal_connect_swapped (item, "activate",
874 G_CALLBACK (individual_info_menu_item_activate_cb),
881 individual_edit_menu_item_activate_cb (FolksIndividual *individual)
883 empathy_individual_edit_dialog_show (individual, NULL);
887 empathy_individual_edit_menu_item_new (FolksIndividual *individual)
889 EmpathyIndividualManager *manager;
892 gboolean enable = FALSE;
893 EmpathyContact *contact;
895 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
897 contact = empathy_contact_dup_from_folks_individual (individual);
899 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
901 if (empathy_individual_manager_initialized ())
903 TpConnection *connection;
905 manager = empathy_individual_manager_dup_singleton ();
906 connection = empathy_contact_get_connection (contact);
908 enable = (empathy_connection_can_alias_personas (connection) &&
909 empathy_connection_can_group_personas (connection));
911 g_object_unref (manager);
914 item = gtk_image_menu_item_new_with_mnemonic (
915 C_("Edit individual (contextual menu)", "_Edit"));
916 image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
917 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
918 gtk_widget_show (image);
920 gtk_widget_set_sensitive (item, enable);
922 g_signal_connect_swapped (item, "activate",
923 G_CALLBACK (individual_edit_menu_item_activate_cb), individual);
925 g_object_unref (contact);
931 empathy_individual_link_menu_item_new (FolksIndividual *individual)
934 /*GtkWidget *image;*/
936 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
938 item = gtk_image_menu_item_new_with_mnemonic (
939 /* Translators: this is a verb meaning "to connect two contacts together
940 * to form a meta-contact". */
941 C_("Link individual (contextual menu)", "_Link Contacts…"));
943 /*image = gtk_image_new_from_icon_name (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
944 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
945 gtk_widget_show (image);*/
947 /* Only allow trusted Individuals to be linked */
948 gtk_widget_set_sensitive (item,
949 folks_individual_get_trust_level (individual) ==
950 FOLKS_TRUST_LEVEL_PERSONAS);
957 FolksIndividual *individual;
958 EmpathyContact *contact;
959 EmpathyChatroom *chatroom;
962 static RoomSubMenuData *
963 room_sub_menu_data_new (FolksIndividual *individual,
964 EmpathyContact *contact,
965 EmpathyChatroom *chatroom)
967 RoomSubMenuData *data;
969 data = g_slice_new0 (RoomSubMenuData);
970 if (individual != NULL)
971 data->individual = g_object_ref (individual);
973 data->contact = g_object_ref (contact);
974 data->chatroom = g_object_ref (chatroom);
980 room_sub_menu_data_free (RoomSubMenuData *data)
982 tp_clear_object (&data->individual);
983 tp_clear_object (&data->contact);
984 g_object_unref (data->chatroom);
985 g_slice_free (RoomSubMenuData, data);
989 room_sub_menu_activate_cb (GtkWidget *item,
990 RoomSubMenuData *data)
993 EmpathyChatroomManager *mgr;
994 EmpathyContact *contact = NULL;
996 chat = empathy_chatroom_get_tp_chat (data->chatroom);
999 /* channel was invalidated. Ignoring */
1003 mgr = empathy_chatroom_manager_dup_singleton (NULL);
1005 if (data->contact != NULL)
1006 contact = g_object_ref (data->contact);
1012 /* find the first of this Individual's contacts who can join this room */
1013 personas = folks_individual_get_personas (data->individual);
1015 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
1016 while (gee_iterator_next (iter) && (contact == NULL))
1018 TpfPersona *persona = gee_iterator_get (iter);
1019 TpContact *tp_contact;
1022 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
1024 tp_contact = tpf_persona_get_contact (persona);
1025 contact = empathy_contact_dup_from_tp_contact (tp_contact);
1027 rooms = empathy_chatroom_manager_get_chatrooms (mgr,
1028 empathy_contact_get_account (contact));
1030 if (g_list_find (rooms, data->chatroom) == NULL)
1031 g_clear_object (&contact);
1033 /* if contact != NULL here, we've found our match */
1035 g_list_free (rooms);
1037 g_clear_object (&persona);
1039 g_clear_object (&iter);
1042 g_object_unref (mgr);
1044 if (contact == NULL)
1046 /* contact disappeared. Ignoring */
1050 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
1052 /* send invitation */
1053 empathy_contact_list_add (EMPATHY_CONTACT_LIST (chat),
1054 contact, _("Inviting you to this room"));
1057 g_object_unref (contact);
1061 create_room_sub_menu (FolksIndividual *individual,
1062 EmpathyContact *contact,
1063 EmpathyChatroom *chatroom)
1066 RoomSubMenuData *data;
1068 item = gtk_menu_item_new_with_label (empathy_chatroom_get_name (chatroom));
1069 data = room_sub_menu_data_new (individual, contact, chatroom);
1070 g_signal_connect_data (item, "activate",
1071 G_CALLBACK (room_sub_menu_activate_cb), data,
1072 (GClosureNotify) room_sub_menu_data_free, 0);
1078 empathy_individual_invite_menu_item_new (FolksIndividual *individual,
1079 EmpathyContact *contact)
1083 GtkWidget *room_item;
1084 EmpathyChatroomManager *mgr;
1085 GList *rooms = NULL;
1086 GList *names = NULL;
1088 GtkWidget *submenu = NULL;
1089 /* map of chat room names to their objects; just a utility to remove
1090 * duplicates and to make construction of the alphabetized list easier */
1091 GHashTable *name_room_map;
1093 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual) ||
1094 EMPATHY_IS_CONTACT (contact),
1097 name_room_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
1100 item = gtk_image_menu_item_new_with_mnemonic (_("_Invite to Chat Room"));
1101 image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_GROUP_MESSAGE,
1102 GTK_ICON_SIZE_MENU);
1103 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
1105 mgr = empathy_chatroom_manager_dup_singleton (NULL);
1107 if (contact != NULL)
1109 rooms = empathy_chatroom_manager_get_chatrooms (mgr,
1110 empathy_contact_get_account (contact));
1117 /* find the first of this Individual's contacts who can join this room */
1118 personas = folks_individual_get_personas (individual);
1119 iter = gee_iterable_iterator (GEE_ITERABLE (personas));
1120 while (gee_iterator_next (iter))
1122 TpfPersona *persona = gee_iterator_get (iter);
1124 TpContact *tp_contact;
1125 EmpathyContact *contact_cur;
1127 if (empathy_folks_persona_is_interesting (FOLKS_PERSONA (persona)))
1129 tp_contact = tpf_persona_get_contact (persona);
1130 contact_cur = empathy_contact_dup_from_tp_contact (tp_contact);
1132 rooms_cur = empathy_chatroom_manager_get_chatrooms (mgr,
1133 empathy_contact_get_account (contact_cur));
1134 rooms = g_list_concat (rooms, rooms_cur);
1136 g_object_unref (contact_cur);
1138 g_clear_object (&persona);
1140 g_clear_object (&iter);
1143 /* alphabetize the rooms */
1144 for (l = rooms; l != NULL; l = g_list_next (l))
1146 EmpathyChatroom *chatroom = l->data;
1149 if (empathy_chatroom_get_tp_chat (chatroom) != NULL)
1153 name = empathy_chatroom_get_name (chatroom);
1154 existed = (g_hash_table_lookup (name_room_map, name) != NULL);
1155 g_hash_table_insert (name_room_map, (gpointer) name,
1156 g_object_ref (chatroom));
1158 /* this will take care of duplicates in rooms */
1161 names = g_list_insert_sorted (names, (gpointer) name,
1162 (GCompareFunc) g_strcmp0);
1167 for (l = names; l != NULL; l = g_list_next (l))
1169 const gchar *name = l->data;
1170 EmpathyChatroom *chatroom;
1172 if (G_UNLIKELY (submenu == NULL))
1173 submenu = gtk_menu_new ();
1175 chatroom = g_hash_table_lookup (name_room_map, name);
1176 room_item = create_room_sub_menu (individual, contact, chatroom);
1177 gtk_menu_shell_append ((GtkMenuShell *) submenu, room_item);
1178 gtk_widget_show (room_item);
1182 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu);
1184 gtk_widget_set_sensitive (item, FALSE);
1186 gtk_widget_show (image);
1188 g_hash_table_destroy (name_room_map);
1189 g_object_unref (mgr);
1190 g_list_free (names);
1191 g_list_free (rooms);