]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/empathy-new-message-dialog.c
switch new message dialog to use an header bar
[empathy.git] / libempathy-gtk / empathy-new-message-dialog.c
index 3e6e3f11d3a10ecf8a8a7b727f042db81fd6d7cc..aa55ae01d74821bfa250afeac2d4ffe473af62e2 100644 (file)
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2007-2008 Collabora Ltd.
  *
  * Authors: Xavier Claessens <xclaesse@gmail.com>
  */
 
-#include <config.h>
-
-#include <string.h>
-#include <stdlib.h>
+#include "config.h"
+#include "empathy-new-message-dialog.h"
 
-#include <gtk/gtk.h>
 #include <glib/gi18n-lib.h>
 
-#include <libmissioncontrol/mc-account.h>
-#include <libmissioncontrol/mission-control.h>
-
-#include <libempathy/empathy-call-factory.h>
-#include <libempathy/empathy-tp-contact-factory.h>
-#include <libempathy/empathy-contact-manager.h>
-#include <libempathy/empathy-dispatcher.h>
-#include <libempathy/empathy-utils.h>
+#include "empathy-request-util.h"
+#include "empathy-contact-chooser.h"
+#include "empathy-ui-utils.h"
+#include "empathy-images.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
-#include <libempathy/empathy-debug.h>
+#include "empathy-debug.h"
 
-#include <libempathy-gtk/empathy-ui-utils.h>
+static EmpathyNewMessageDialog *dialog_singleton = NULL;
 
-#include "empathy-new-message-dialog.h"
-#include "empathy-account-chooser.h"
+G_DEFINE_TYPE(EmpathyNewMessageDialog, empathy_new_message_dialog,
+    GTK_TYPE_DIALOG)
+
+struct _EmpathyNewMessageDialogPriv {
+  GtkWidget *chooser;
+  GtkWidget *button_chat;
+  GtkWidget *button_sms;
+};
 
 /**
  * SECTION:empathy-new-message-dialog
  * @short_description: A dialog to show a new message
  * @include: libempathy-gtk/empathy-new-message-dialog.h
  *
- * #EmpathyNewMessageDialog is a dialog which allows a text chat or
- * call to be started with any contact on any enabled account.
+ * #EmpathyNewMessageDialog is a dialog which allows a text chat
+ * to be started with any contact on any enabled account.
  */
 
-typedef struct {
-       GtkWidget *dialog;
-       GtkWidget *table_contact;
-       GtkWidget *account_chooser;
-       GtkWidget *entry_id;
-       GtkWidget *button_chat;
-       GtkWidget *button_call;
-       EmpathyContactManager *contact_manager;
-} EmpathyNewMessageDialog;
-
-enum {
-       COMPLETION_COL_TEXT,
-       COMPLETION_COL_ID,
-       COMPLETION_COL_NAME,
-} CompletionCol;
+enum
+{
+  EMP_NEW_MESSAGE_TEXT,
+  EMP_NEW_MESSAGE_SMS,
+};
+
+static const gchar *
+get_error_display_message (GError *error)
+{
+  if (error->domain != TP_ERROR)
+    goto out;
+
+  switch (error->code)
+    {
+      case TP_ERROR_NETWORK_ERROR:
+        return _("Network error");
+      case TP_ERROR_OFFLINE:
+        return _("The contact is offline");
+      case TP_ERROR_INVALID_HANDLE:
+        return _("The specified contact is either invalid or unknown");
+      case TP_ERROR_NOT_CAPABLE:
+        return _("The contact does not support this kind of conversation");
+      case TP_ERROR_NOT_IMPLEMENTED:
+        return _("The requested functionality is not implemented "
+                 "for this protocol");
+      case TP_ERROR_INVALID_ARGUMENT:
+        /* Not very user friendly to say 'invalid arguments' */
+        break;
+      case TP_ERROR_NOT_AVAILABLE:
+        return _("Could not start a conversation with the given contact");
+      case TP_ERROR_CHANNEL_BANNED:
+        return _("You are banned from this channel");
+      case TP_ERROR_CHANNEL_FULL:
+        return _("This channel is full");
+      case TP_ERROR_CHANNEL_INVITE_ONLY:
+        return _("You must be invited to join this channel");
+      case TP_ERROR_DISCONNECTED:
+        return _("Can't proceed while disconnected");
+      case TP_ERROR_PERMISSION_DENIED:
+        return _("Permission denied");
+      default:
+        DEBUG ("Unhandled error code: %d", error->code);
+    }
+
+out:
+  return _("There was an error starting the conversation");
+}
 
 static void
-new_message_dialog_account_changed_cb (GtkWidget               *widget,
-                                      EmpathyNewMessageDialog *dialog)
+show_chat_error (GError *error,
+    GtkWindow *parent)
 {
-       EmpathyAccountChooser *chooser;
-       TpConnection          *connection;
-       EmpathyTpContactList *contact_list;
-       GList                *members;
-       GtkListStore         *store;
-       GtkEntryCompletion   *completion;
-       GtkTreeIter           iter;
-       gchar                *tmpstr;
-
-       /* Remove completions */
-       completion = gtk_entry_get_completion (GTK_ENTRY (dialog->entry_id));
-       store = GTK_LIST_STORE (gtk_entry_completion_get_model (completion));
-       gtk_list_store_clear (store);
-
-       /* Get members of the new account */
-       chooser = EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser);
-       connection = empathy_account_chooser_get_connection (chooser);
-       if (!connection) {
-               return;
-       }
-       contact_list = empathy_contact_manager_get_list (dialog->contact_manager,
-                                                        connection);
-       members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list));
-
-       /* Add members to the completion */
-       while (members) {
-               EmpathyContact *contact = members->data;
-
-               if (empathy_contact_is_online (contact)) {
-                       DEBUG ("Adding contact ID %s, Name %s",
-                              empathy_contact_get_id (contact),
-                              empathy_contact_get_name (contact));
-
-                       tmpstr = g_strdup_printf ("%s (%s)",
-                               empathy_contact_get_name (contact),
-                               empathy_contact_get_id (contact));
-
-                       gtk_list_store_insert_with_values (store, &iter, -1,
-                               COMPLETION_COL_TEXT, tmpstr,
-                               COMPLETION_COL_ID, empathy_contact_get_id (contact),
-                               COMPLETION_COL_NAME, empathy_contact_get_name (contact),
-                               -1);
-
-                       g_free (tmpstr);
-               }
-
-               g_object_unref (contact);
-               members = g_list_delete_link (members, members);
-       }
+  GtkWidget *dialog;
+
+  dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL,
+      GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+      "%s",
+      get_error_display_message (error));
+
+  g_signal_connect_swapped (dialog, "response",
+      G_CALLBACK (gtk_widget_destroy),
+      dialog);
+
+  gtk_widget_show (dialog);
 }
 
-static gboolean
-new_message_dialog_match_selected_cb (GtkEntryCompletion *widget,
-                                     GtkTreeModel       *model,
-                                     GtkTreeIter        *iter,
-                                     EmpathyNewMessageDialog *dialog)
+static void
+ensure_text_channel_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
 {
-       gchar *id;
+  GError *error = NULL;
+
+  if (!tp_account_channel_request_ensure_channel_finish (
+        TP_ACCOUNT_CHANNEL_REQUEST (source), result, &error))
+    {
+      DEBUG ("Failed to ensure text channel: %s", error->message);
+      show_chat_error (error, user_data);
+      g_error_free (error);
+    }
+}
 
-       if (!iter || !model) {
-               return FALSE;
-       }
+static void
+empathy_new_message_dialog_response (GtkDialog *dialog,
+    int response_id)
+{
+  EmpathyNewMessageDialog *self = (EmpathyNewMessageDialog *) dialog;
+  FolksIndividual *individual = NULL;
+  EmpathyContact *contact = NULL;
+
+  if (response_id < EMP_NEW_MESSAGE_TEXT)
+    goto out;
+
+  individual = empathy_contact_chooser_dup_selected (
+      EMPATHY_CONTACT_CHOOSER (self->priv->chooser));
+  if (individual == NULL)
+    goto out;
+
+  switch (response_id)
+    {
+      case EMP_NEW_MESSAGE_TEXT:
+        contact = empathy_contact_dup_best_for_action (individual,
+            EMPATHY_ACTION_CHAT);
+        g_return_if_fail (contact != NULL);
+
+        empathy_chat_with_contact_id (empathy_contact_get_account (contact),
+            empathy_contact_get_id (contact),
+            empathy_get_current_action_time (),
+            ensure_text_channel_cb,
+            gtk_widget_get_parent_window (GTK_WIDGET (dialog)));
+        break;
+
+      case EMP_NEW_MESSAGE_SMS:
+        contact = empathy_contact_dup_best_for_action (individual,
+            EMPATHY_ACTION_SMS);
+        g_return_if_fail (contact != NULL);
+
+        empathy_sms_contact_id (empathy_contact_get_account (contact),
+            empathy_contact_get_id (contact),
+            empathy_get_current_action_time (),
+            ensure_text_channel_cb,
+            gtk_widget_get_parent_window (GTK_WIDGET (dialog)));
+        break;
+
+      default:
+        g_warn_if_reached ();
+    }
+
+out:
+  tp_clear_object (&individual);
+  tp_clear_object (&contact);
+  gtk_widget_destroy (GTK_WIDGET (dialog));
+}
 
-       gtk_tree_model_get (model, iter, COMPLETION_COL_ID, &id, -1);
-       gtk_entry_set_text (GTK_ENTRY (dialog->entry_id), id);
+static GObject *
+empathy_new_message_dialog_constructor (GType type,
+    guint n_props,
+    GObjectConstructParam *props)
+{
+  GObject *retval;
+
+  if (dialog_singleton)
+    {
+      retval = G_OBJECT (dialog_singleton);
+      g_object_ref (retval);
+    }
+  else
+    {
+      retval = G_OBJECT_CLASS (
+      empathy_new_message_dialog_parent_class)->constructor (type,
+        n_props, props);
+
+      dialog_singleton = EMPATHY_NEW_MESSAGE_DIALOG (retval);
+      g_object_add_weak_pointer (retval, (gpointer) &dialog_singleton);
+    }
+
+  return retval;
+}
 
-       DEBUG ("Got selected match **%s**", id);
+static gboolean
+individual_supports_action (FolksIndividual *individual,
+    EmpathyActionType action)
+{
+  EmpathyContact *contact;
 
-       g_free (id);
+  contact = empathy_contact_dup_best_for_action (individual, action);
+  if (contact == NULL)
+    return FALSE;
 
-       return TRUE;
+  g_object_unref (contact);
+  return TRUE;
 }
 
 static gboolean
-new_message_dialog_match_func (GtkEntryCompletion *completion,
-                              const gchar        *key,
-                              GtkTreeIter        *iter,
-                              gpointer            user_data)
+filter_individual (EmpathyContactChooser *chooser,
+    FolksIndividual *individual,
+    gboolean is_online,
+    gboolean searching,
+    gpointer user_data)
 {
-       GtkTreeModel *model;
-       gchar        *id;
-       gchar        *name;
-
-       model = gtk_entry_completion_get_model (completion);
-       if (!model || !iter) {
-               return FALSE;
-       }
-
-       gtk_tree_model_get (model, iter, COMPLETION_COL_NAME, &name, -1);
-       if (strstr (name, key)) {
-               DEBUG ("Key %s is matching name **%s**", key, name);
-               g_free (name);
-               return TRUE;
-       }
-       g_free (name);
-
-       gtk_tree_model_get (model, iter, COMPLETION_COL_ID, &id, -1);
-       if (strstr (id, key)) {
-               DEBUG ("Key %s is matching ID **%s**", key, id);
-               g_free (id);
-               return TRUE;
-       }
-       g_free (id);
-
-       return FALSE;
+  return individual_supports_action (individual, EMPATHY_ACTION_CHAT) ||
+    individual_supports_action (individual, EMPATHY_ACTION_SMS);
 }
 
 static void
-new_message_dialog_call_got_contact_cb (EmpathyTpContactFactory *factory,
-                                       EmpathyContact          *contact,
-                                       const GError            *error,
-                                       gpointer                 user_data,
-                                       GObject                 *weak_object)
+selection_changed_cb (GtkWidget *chooser,
+    FolksIndividual *selected,
+    EmpathyNewMessageDialog *self)
 {
-       EmpathyCallFactory *call_factory;
-
-       if (error != NULL) {
-               DEBUG ("Error: %s", error->message);
-               return;
-       }
-
-       call_factory = empathy_call_factory_get();
-       empathy_call_factory_new_call (call_factory, contact);
+  gboolean can_chat, can_sms;
+
+  if (selected == NULL)
+    {
+      can_chat = can_sms = FALSE;
+    }
+  else
+    {
+      can_chat = individual_supports_action (selected, EMPATHY_ACTION_CHAT);
+      can_sms = individual_supports_action (selected, EMPATHY_ACTION_SMS);
+    }
+
+  gtk_widget_set_sensitive (self->priv->button_chat, can_chat);
+#if 0
+  gtk_widget_set_sensitive (self->priv->button_sms, can_sms);
+#endif
 }
 
 static void
-new_message_dialog_response_cb (GtkWidget               *widget,
-                               gint                    response,
-                               EmpathyNewMessageDialog *dialog)
+selection_activate_cb (GtkWidget *chooser,
+    EmpathyNewMessageDialog *self)
 {
-       TpConnection *connection;
-       const gchar *id;
-
-       connection = empathy_account_chooser_get_connection (
-               EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser));
-       id = gtk_entry_get_text (GTK_ENTRY (dialog->entry_id));
-       if (!connection || EMP_STR_EMPTY (id)) {
-               gtk_widget_destroy (widget);
-               return;
-       }
-
-       if (response == 1) {
-               EmpathyTpContactFactory *factory;
-
-               factory = empathy_tp_contact_factory_dup_singleton (connection);
-               empathy_tp_contact_factory_get_from_id (factory, id,
-                       new_message_dialog_call_got_contact_cb,
-                       NULL, NULL, NULL);
-               g_object_unref (factory);
-       } else if (response == 2) {
-               empathy_dispatcher_chat_with_contact_id (connection, id, NULL, NULL);
-       }
-
-       gtk_widget_destroy (widget);
+  gtk_dialog_response (GTK_DIALOG (self), EMP_NEW_MESSAGE_TEXT);
 }
 
 static void
-new_message_change_state_button_cb  (GtkEditable             *editable,
-                                    EmpathyNewMessageDialog *dialog)  
+empathy_new_message_dialog_init (EmpathyNewMessageDialog *self)
 {
-       const gchar *id;
-       gboolean     sensitive;
-
-       id = gtk_entry_get_text (GTK_ENTRY (editable));
-       sensitive = !EMP_STR_EMPTY (id);
-       
-       gtk_widget_set_sensitive (dialog->button_chat, sensitive);
-       gtk_widget_set_sensitive (dialog->button_call, sensitive);
+  GtkWidget *image;
+  GtkWidget *content;
+
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+      EMPATHY_TYPE_NEW_MESSAGE_DIALOG, EmpathyNewMessageDialogPriv);
+
+  content = gtk_dialog_get_content_area (GTK_DIALOG (self));
+
+  /* contact chooser */
+  self->priv->chooser = empathy_contact_chooser_new ();
+
+  empathy_contact_chooser_set_filter_func (
+      EMPATHY_CONTACT_CHOOSER (self->priv->chooser), filter_individual, self);
+
+  gtk_box_pack_start (GTK_BOX (content), self->priv->chooser, TRUE, TRUE, 0);
+  gtk_widget_show (self->priv->chooser);
+
+  g_signal_connect (self->priv->chooser, "selection-changed",
+      G_CALLBACK (selection_changed_cb), self);
+  g_signal_connect (self->priv->chooser, "activate",
+      G_CALLBACK (selection_activate_cb), self);
+
+  /* close button */
+  gtk_dialog_add_button (GTK_DIALOG (self),
+      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+#if 0
+  /* add SMS button */
+  self->priv->button_sms = gtk_button_new_with_mnemonic (_("_SMS"));
+  image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_SMS,
+      GTK_ICON_SIZE_BUTTON);
+  gtk_button_set_image (GTK_BUTTON (self->priv->button_sms), image);
+#endif
+
+  /* add chat button */
+  self->priv->button_chat = gtk_button_new_with_mnemonic (_("_Done"));
+  image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_NEW_MESSAGE,
+      GTK_ICON_SIZE_BUTTON);
+  gtk_button_set_image (GTK_BUTTON (self->priv->button_chat), image);
+
+#if 0
+  gtk_dialog_add_action_widget (GTK_DIALOG (self), self->priv->button_sms,
+      EMP_NEW_MESSAGE_SMS);
+  gtk_widget_show (self->priv->button_sms);
+#endif
+
+  gtk_dialog_add_action_widget (GTK_DIALOG (self), self->priv->button_chat,
+      EMP_NEW_MESSAGE_TEXT);
+  gtk_widget_show (self->priv->button_chat);
+
+  /* Tweak the dialog */
+  gtk_window_set_title (GTK_WINDOW (self), _("New Conversation"));
+  gtk_window_set_role (GTK_WINDOW (self), "new_message");
+
+  /* Set a default height so a few contacts are displayed */
+  gtk_window_set_default_size (GTK_WINDOW (self), -1, 600);
+
+  gtk_widget_set_sensitive (self->priv->button_chat, FALSE);
+#if 0
+  gtk_widget_set_sensitive (self->priv->button_sms, FALSE);
+#endif
 }
 
 static void
-new_message_dialog_destroy_cb (GtkWidget               *widget,
-                              EmpathyNewMessageDialog *dialog)
+empathy_new_message_dialog_class_init (
+  EmpathyNewMessageDialogClass *class)
 {
-       g_object_unref (dialog->contact_manager);
-       g_free (dialog);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (class);
+
+  object_class->constructor = empathy_new_message_dialog_constructor;
+
+  dialog_class->response = empathy_new_message_dialog_response;
+
+  g_type_class_add_private (class, sizeof (EmpathyNewMessageDialogPriv));
 }
 
 /**
- * empathy_new_message_dialog_show:
+ * empathy_new_message_dialog_new:
  * @parent: parent #GtkWindow of the dialog
  *
- * Create a new #EmpathyNewMessageDialog and show it.
+ * Create a new #EmpathyNewMessageDialog it.
  *
  * Return value: the new #EmpathyNewMessageDialog
  */
 GtkWidget *
 empathy_new_message_dialog_show (GtkWindow *parent)
 {
-       static EmpathyNewMessageDialog *dialog = NULL;
-       GtkBuilder                     *gui;
-       gchar                          *filename;
-       GtkEntryCompletion             *completion;
-       GtkListStore                   *model;
-
-       if (dialog) {
-               gtk_window_present (GTK_WINDOW (dialog->dialog));
-               return dialog->dialog;
-       }
-
-       dialog = g_new0 (EmpathyNewMessageDialog, 1);
-
-       /* create a contact manager */
-       dialog->contact_manager = empathy_contact_manager_dup_singleton ();
-
-       filename = empathy_file_lookup ("empathy-new-message-dialog.ui",
-                                       "libempathy-gtk");
-       gui = empathy_builder_get_file (filename,
-                                       "new_message_dialog", &dialog->dialog,
-                                       "table_contact", &dialog->table_contact,
-                                       "entry_id", &dialog->entry_id,
-                                       "button_chat", &dialog->button_chat,
-                                       "button_call",&dialog->button_call,
-                                       NULL);
-       g_free (filename);
-
-       /* text completion */
-       completion = gtk_entry_completion_new ();
-       model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
-       gtk_entry_completion_set_text_column (completion, COMPLETION_COL_TEXT);
-       gtk_entry_completion_set_match_func (completion,
-                                            new_message_dialog_match_func,
-                                            NULL, NULL);
-       gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (model));
-       gtk_entry_set_completion (GTK_ENTRY (dialog->entry_id), completion);
-       g_signal_connect (completion, "match-selected",
-                         G_CALLBACK (new_message_dialog_match_selected_cb),
-                         dialog);
-       g_object_unref(completion);
-       g_object_unref(model);
-
-       empathy_builder_connect (gui, dialog,
-                              "new_message_dialog", "destroy", new_message_dialog_destroy_cb,
-                              "new_message_dialog", "response", new_message_dialog_response_cb,
-                              "entry_id", "changed", new_message_change_state_button_cb,
-                              NULL);
-
-       g_object_add_weak_pointer (G_OBJECT (dialog->dialog), (gpointer) &dialog);
-
-       g_object_unref (gui);
-
-       /* Create account chooser */
-       dialog->account_chooser = empathy_account_chooser_new ();
-       gtk_table_attach_defaults (GTK_TABLE (dialog->table_contact),
-                                  dialog->account_chooser,
-                                  1, 2, 0, 1);
-       empathy_account_chooser_set_filter (EMPATHY_ACCOUNT_CHOOSER (dialog->account_chooser),
-                                           empathy_account_chooser_filter_is_connected,
-                                           NULL);
-       gtk_widget_show (dialog->account_chooser);
-
-       new_message_dialog_account_changed_cb (dialog->account_chooser, dialog);
-       g_signal_connect (dialog->account_chooser, "changed", 
-                         G_CALLBACK (new_message_dialog_account_changed_cb),
-                         dialog);
-
-       if (parent) {
-               gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog),
-                                             GTK_WINDOW (parent));
-       }
-
-       gtk_widget_set_sensitive (dialog->button_chat, FALSE);
-       gtk_widget_set_sensitive (dialog->button_call, FALSE);
-
-       gtk_widget_show (dialog->dialog);
-
-       return dialog->dialog;
+  GtkWidget *dialog;
+
+  dialog = g_object_new (EMPATHY_TYPE_NEW_MESSAGE_DIALOG,
+                  "use-header-bar", 1,
+                  NULL);
+
+  if (parent)
+    {
+      gtk_window_set_transient_for (GTK_WINDOW (dialog),
+          GTK_WINDOW (parent));
+    }
+
+  gtk_widget_show (dialog);
+  return dialog;
 }