/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007-2010 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: Xavier Claessens * Philip Withnall * Travis Reitter */ #include "config.h" #include "empathy-individual-information-dialog.h" #include #include "empathy-individual-manager.h" #include "empathy-individual-widget.h" #include "empathy-pkg-kit.h" #include "empathy-ui-utils.h" #include "empathy-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT #include "empathy-debug.h" #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIndividualInformationDialog) typedef struct { FolksIndividual *individual; GtkWidget *individual_widget; /* child widget */ GtkWidget *label; /* child widget */ } EmpathyIndividualInformationDialogPriv; enum { PROP_0, PROP_INDIVIDUAL, }; /* Info dialogs currently open. * Each dialog contains a referenced pointer to its Individual */ static GList *information_dialogs = NULL; static void individual_information_dialog_set_individual ( EmpathyIndividualInformationDialog *dialog, FolksIndividual *individual); G_DEFINE_TYPE (EmpathyIndividualInformationDialog, empathy_individual_information_dialog, GTK_TYPE_DIALOG); static void individual_dialogs_response_cb (GtkDialog *dialog, gint response, GList **dialogs) { *dialogs = g_list_remove (*dialogs, dialog); gtk_widget_destroy (GTK_WIDGET (dialog)); } static gint individual_dialogs_find (GObject *object, FolksIndividual *individual) { EmpathyIndividualInformationDialogPriv *priv = GET_PRIV (object); return individual != priv->individual; } void empathy_individual_information_dialog_show (FolksIndividual *individual, GtkWindow *parent) { GtkWidget *dialog; GList *l; g_return_if_fail (FOLKS_IS_INDIVIDUAL (individual)); g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent)); l = g_list_find_custom (information_dialogs, individual, (GCompareFunc) individual_dialogs_find); if (l != NULL) { gtk_window_present (GTK_WINDOW (l->data)); return; } /* Create dialog */ dialog = g_object_new (EMPATHY_TYPE_INDIVIDUAL_INFORMATION_DIALOG, "individual", individual, NULL); information_dialogs = g_list_prepend (information_dialogs, dialog); gtk_widget_show (dialog); } static void individual_removed_cb (FolksIndividual *individual, FolksIndividual *replacement_individual, EmpathyIndividualInformationDialog *self) { individual_information_dialog_set_individual (self, replacement_individual); /* Destroy the dialogue */ if (replacement_individual == NULL) { individual_dialogs_response_cb (GTK_DIALOG (self), GTK_RESPONSE_DELETE_EVENT, &information_dialogs); } } static void set_label_visibility (EmpathyIndividualInformationDialog *dialog) { EmpathyIndividualInformationDialogPriv *priv = GET_PRIV (dialog); guint num_personas = 0; /* Count how many Telepathy personas we have, to see whether we can * unlink */ if (priv->individual != NULL) { GeeSet *personas; GeeIterator *iter; personas = folks_individual_get_personas (priv->individual); iter = gee_iterable_iterator (GEE_ITERABLE (personas)); while (gee_iterator_next (iter)) { FolksPersona *persona = gee_iterator_get (iter); if (empathy_folks_persona_is_interesting (persona)) num_personas++; g_clear_object (&persona); } g_clear_object (&iter); } /* Only make the label visible if we have enough personas */ gtk_widget_set_visible (priv->label, (num_personas > 1) ? TRUE : FALSE); } static void individual_information_dialog_set_individual ( EmpathyIndividualInformationDialog *dialog, FolksIndividual *individual) { EmpathyIndividualInformationDialogPriv *priv; g_return_if_fail (EMPATHY_INDIVIDUAL_INFORMATION_DIALOG (dialog)); g_return_if_fail (individual == NULL || FOLKS_IS_INDIVIDUAL (individual)); priv = GET_PRIV (dialog); /* Remove the old Individual */ if (priv->individual != NULL) { g_signal_handlers_disconnect_by_func (priv->individual, (GCallback) individual_removed_cb, dialog); } tp_clear_object (&priv->individual); /* Add the new Individual */ priv->individual = individual; if (individual != NULL) { g_object_ref (individual); g_signal_connect (individual, "removed", (GCallback) individual_removed_cb, dialog); /* Update the UI */ gtk_window_set_title (GTK_WINDOW (dialog), folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (individual))); empathy_individual_widget_set_individual ( EMPATHY_INDIVIDUAL_WIDGET (priv->individual_widget), individual); set_label_visibility (dialog); } } static void individual_information_dialog_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec) { EmpathyIndividualInformationDialogPriv *priv = GET_PRIV (object); switch (param_id) { case PROP_INDIVIDUAL: g_value_set_object (value, priv->individual); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; }; } static void individual_information_dialog_set_property (GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { EmpathyIndividualInformationDialog *dialog = EMPATHY_INDIVIDUAL_INFORMATION_DIALOG (object); switch (param_id) { case PROP_INDIVIDUAL: individual_information_dialog_set_individual (dialog, FOLKS_INDIVIDUAL (g_value_get_object (value))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); break; }; } static void individual_information_dialog_dispose (GObject *object) { individual_information_dialog_set_individual ( EMPATHY_INDIVIDUAL_INFORMATION_DIALOG (object), NULL); G_OBJECT_CLASS ( empathy_individual_information_dialog_parent_class)->dispose (object); } static void empathy_individual_information_dialog_class_init ( EmpathyIndividualInformationDialogClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = individual_information_dialog_dispose; object_class->get_property = individual_information_dialog_get_property; object_class->set_property = individual_information_dialog_set_property; g_object_class_install_property (object_class, PROP_INDIVIDUAL, g_param_spec_object ("individual", "Folks Individual", "Folks Individual to base the dialog upon", FOLKS_TYPE_INDIVIDUAL, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_type_class_add_private (object_class, sizeof (EmpathyIndividualInformationDialogPriv)); } static void empathy_individual_information_dialog_init ( EmpathyIndividualInformationDialog *dialog) { GtkWidget *button; GtkBox *content_area; gchar *label_string; EmpathyIndividualInformationDialogPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE ( dialog, EMPATHY_TYPE_INDIVIDUAL_INFORMATION_DIALOG, EmpathyIndividualInformationDialogPriv); dialog->priv = priv; priv->individual = NULL; gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE); content_area = GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))); /* Translators: the heading at the top of the Information dialogue */ label_string = g_strdup_printf ("%s", _("Linked Contacts")); priv->label = gtk_label_new (NULL); gtk_label_set_markup (GTK_LABEL (priv->label), label_string); g_free (label_string); gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5); gtk_misc_set_padding (GTK_MISC (priv->label), 6, 6); gtk_box_pack_start (content_area, priv->label, FALSE, TRUE, 0); gtk_widget_show (priv->label); /* Individual widget */ priv->individual_widget = empathy_individual_widget_new (priv->individual, EMPATHY_INDIVIDUAL_WIDGET_SHOW_LOCATION | EMPATHY_INDIVIDUAL_WIDGET_SHOW_DETAILS | EMPATHY_INDIVIDUAL_WIDGET_SHOW_PERSONAS); gtk_container_set_border_width (GTK_CONTAINER (priv->individual_widget), 6); gtk_box_pack_start (content_area, priv->individual_widget, TRUE, TRUE, 0); gtk_widget_show (priv->individual_widget); /* Close button */ button = gtk_button_new_with_label (GTK_STOCK_CLOSE); gtk_button_set_use_stock (GTK_BUTTON (button), TRUE); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_CLOSE); gtk_widget_set_can_default (button, TRUE); gtk_window_set_default (GTK_WINDOW (dialog), button); gtk_widget_show (button); g_signal_connect (dialog, "response", G_CALLBACK (individual_dialogs_response_cb), &information_dialogs); } static void show_gnome_contacts_error_dialog (void) { GtkWidget *dialog; dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("gnome-contacts not installed")); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("Please install gnome-contacts to access contacts details.")); g_signal_connect_swapped (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); gtk_widget_show (dialog); } static void start_gnome_contacts (FolksIndividual *individual, gboolean try_installing); static void install_gnome_contacts_cb (GObject *source, GAsyncResult *result, gpointer user_data) { FolksIndividual *individual = user_data; GError *error = NULL; if (!empathy_pkg_kit_install_packages_finish (result, &error)) { DEBUG ("Failed to install gnome-contacts: %s", error->message); g_error_free (error); show_gnome_contacts_error_dialog (); goto out; } DEBUG ("gnome-contacts installed"); start_gnome_contacts (individual, FALSE); out: g_object_unref (individual); } static void start_gnome_contacts (FolksIndividual *individual, gboolean try_installing) { gchar *args; GError *error = NULL; g_return_if_fail (FOLKS_IS_INDIVIDUAL (individual)); args = g_strdup_printf ("-i %s", folks_individual_get_id (individual)); if (!empathy_launch_external_app ("gnome-contacts.desktop", args, &error)) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { if (try_installing) { const gchar *packages[] = { "gnome-contacts", NULL }; DEBUG ("gnome-contacts not installed; try to install it"); empathy_pkg_kit_install_packages_async (0, packages, NULL, NULL, install_gnome_contacts_cb, g_object_ref (individual)); } else { show_gnome_contacts_error_dialog (); } } } g_free (args); } /* Use gnome-contacts to display @individual or fallback to * EmpathyIndividualInformationDialog if user is not not in Folks. */ void empathy_display_individual_info (FolksIndividual *individual) { EmpathyIndividualManager *mgr; mgr = empathy_individual_manager_dup_singleton (); /* Only use gnome-contacts if that's a 'real' individual we got from * Folks (and so the individual manager knows about it). If not that's a * MUC contact and we use the simple dialog. */ if (empathy_individual_manager_lookup_member (mgr, folks_individual_get_id (individual)) != NULL) { start_gnome_contacts (individual, TRUE); } else { empathy_individual_information_dialog_show (individual, NULL); } g_object_unref (mgr); }