]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/gossip-chat.c
sv.po: Updated Swedish translation
[empathy.git] / libempathy-gtk / gossip-chat.c
index 03f22514af87584257f4ddc5472636f07bad7b6d..1ad76b7f5fc6b8b2a360953280a78cf2978ceb58 100644 (file)
@@ -33,9 +33,9 @@
 #include <gdk/gdkkeysyms.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
-#include <glade/glade.h>
 
 #include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-log-manager.h>
 #include <libempathy/gossip-debug.h>
 #include <libempathy/gossip-utils.h>
 #include <libempathy/gossip-conf.h>
@@ -46,7 +46,7 @@
 #include "gossip-geometry.h"
 #include "gossip-preferences.h"
 #include "gossip-spell.h"
-//#include "gossip-spell-dialog.h"
+#include "gossip-spell-dialog.h"
 #include "gossip-ui-utils.h"
 
 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHAT, GossipChatPriv))
 
 struct _GossipChatPriv {
        EmpathyContactManager *manager;
+       EmpathyLogManager     *log_manager;
        EmpathyTpChat         *tp_chat;
        GossipChatWindow      *window;
-
        GtkTooltips           *tooltips;
        guint                  composing_stop_timeout_id;
        gboolean               sensitive;
        gchar                 *id;
        GSList                *sent_messages;
        gint                   sent_messages_index;
+       GList                 *compositors;
+       guint                  scroll_idle_id;
+       gboolean               first_tp_chat;
+       GossipTime             time_joined;
        /* Used to automatically shrink a window that has temporarily
         * grown due to long input. 
         */
@@ -138,6 +142,8 @@ static void             chat_state_changed_cb             (EmpathyTpChat   *tp_c
                                                           GossipContact   *contact,
                                                           TelepathyChannelChatState  state,
                                                           GossipChat      *chat);
+static void             chat_add_logs                     (GossipChat      *chat);
+static gboolean         chat_scroll_down_idle_func        (GossipChat      *chat);
 
 enum {
        COMPOSING,
@@ -147,7 +153,7 @@ enum {
        LAST_SIGNAL
 };
 
-static guint chat_signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE (GossipChat, gossip_chat, G_TYPE_OBJECT);
 
@@ -160,7 +166,7 @@ gossip_chat_class_init (GossipChatClass *klass)
 
        object_class->finalize = chat_finalize;
 
-       chat_signals[COMPOSING] =
+       signals[COMPOSING] =
                g_signal_new ("composing",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
@@ -170,7 +176,7 @@ gossip_chat_class_init (GossipChatClass *klass)
                              G_TYPE_NONE,
                              1, G_TYPE_BOOLEAN);
 
-       chat_signals[NEW_MESSAGE] =
+       signals[NEW_MESSAGE] =
                g_signal_new ("new-message",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
@@ -180,7 +186,7 @@ gossip_chat_class_init (GossipChatClass *klass)
                              G_TYPE_NONE,
                              2, GOSSIP_TYPE_MESSAGE, G_TYPE_BOOLEAN);
 
-       chat_signals[NAME_CHANGED] =
+       signals[NAME_CHANGED] =
                g_signal_new ("name-changed",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
@@ -190,7 +196,7 @@ gossip_chat_class_init (GossipChatClass *klass)
                              G_TYPE_NONE,
                              1, G_TYPE_POINTER);
 
-       chat_signals[STATUS_CHANGED] =
+       signals[STATUS_CHANGED] =
                g_signal_new ("status-changed",
                              G_OBJECT_CLASS_TYPE (object_class),
                              G_SIGNAL_RUN_LAST,
@@ -226,12 +232,14 @@ gossip_chat_init (GossipChat *chat)
        priv = GET_PRIV (chat);
 
        priv->manager = empathy_contact_manager_new ();
-       priv->tooltips = gtk_tooltips_new ();
+       priv->log_manager = empathy_log_manager_new ();
+       priv->tooltips = g_object_ref_sink (gtk_tooltips_new ());
        priv->default_window_height = -1;
        priv->vscroll_visible = FALSE;
        priv->sensitive = TRUE;
        priv->sent_messages = NULL;
        priv->sent_messages_index = -1;
+       priv->first_tp_chat = TRUE;
 
        g_signal_connect (chat->input_text_view,
                          "key_press_event",
@@ -284,14 +292,23 @@ chat_finalize (GObject *object)
        g_slist_foreach (priv->sent_messages, (GFunc) g_free, NULL);
        g_slist_free (priv->sent_messages);
 
+       g_list_foreach (priv->compositors, (GFunc) g_object_unref, NULL);
+       g_list_free (priv->compositors);
+
        chat_composing_remove_timeout (chat);
        g_object_unref (chat->account);
        g_object_unref (priv->manager);
+       g_object_unref (priv->log_manager);
+       g_object_unref (priv->tooltips);
 
        if (priv->tp_chat) {
                g_object_unref (priv->tp_chat);
        }
 
+       if (priv->scroll_idle_id) {
+               g_source_remove (priv->scroll_idle_id);
+       }
+
        g_free (priv->id);
 
        G_OBJECT_CLASS (gossip_chat_parent_class)->finalize (object);
@@ -302,7 +319,6 @@ chat_destroy_cb (EmpathyTpChat *tp_chat,
                 GossipChat    *chat)
 {
        GossipChatPriv *priv;
-       GtkWidget      *widget;
 
        priv = GET_PRIV (chat);
 
@@ -310,22 +326,22 @@ chat_destroy_cb (EmpathyTpChat *tp_chat,
                g_object_unref (priv->tp_chat);
                priv->tp_chat = NULL;
        }
+       priv->sensitive = FALSE;
 
        gossip_chat_view_append_event (chat->view, _("Disconnected"));
+       gtk_widget_set_sensitive (chat->input_text_view, FALSE);
 
-       widget = gossip_chat_get_widget (chat);
-       gtk_widget_set_sensitive (widget, FALSE);
-       priv->sensitive = FALSE;
+       if (GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat) {
+               GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat (chat, NULL);
+       }
 }
 
 static void
 chat_send (GossipChat  *chat,
           const gchar *msg)
 {
-       GossipChatPriv   *priv;
-       //GossipLogManager *log_manager;
-       GossipMessage    *message;
-       GossipContact    *own_contact;
+       GossipChatPriv *priv;
+       GossipMessage  *message;
 
        priv = GET_PRIV (chat);
 
@@ -340,14 +356,10 @@ chat_send (GossipChat  *chat,
                return;
        }
 
-       /* FIXME: gossip_app_set_not_away ();*/
+       /* FIXME: add here something to let group/privrate chat handle
+        *        some special messages */
 
-       own_contact = gossip_chat_get_own_contact (chat);
        message = gossip_message_new (msg);
-       gossip_message_set_sender (message, own_contact);
-
-       //FIXME: log_manager = gossip_session_get_log_manager (gossip_app_get_session ());
-       //gossip_log_message_for_contact (log_manager, message, FALSE);
 
        empathy_tp_chat_send (priv->tp_chat, message);
 
@@ -385,8 +397,8 @@ chat_message_received_cb (EmpathyTpChat *tp_chat,
                          GossipChat    *chat)
 {
        GossipChatPriv *priv;
-       //GossipLogManager      *log_manager;
-       GossipContact         *sender;
+       GossipContact  *sender;
+       GossipTime      timestamp;
 
        priv = GET_PRIV (chat);
 
@@ -394,17 +406,22 @@ chat_message_received_cb (EmpathyTpChat *tp_chat,
        gossip_debug (DEBUG_DOMAIN, "Appending message ('%s')",
                      gossip_contact_get_name (sender));
 
-/*FIXME:
-       log_manager = gossip_session_get_log_manager (gossip_app_get_session ());
-       gossip_log_message_for_contact (log_manager, message, TRUE);
-*/
+       /* Log the message only if it's not backlog */
+       timestamp = gossip_message_get_timestamp (message);
+       if (timestamp >= priv->time_joined) {
+               empathy_log_manager_add_message (priv->log_manager,
+                                                gossip_chat_get_id (chat),
+                                                gossip_chat_is_group_chat (chat),
+                                                message);
+       }
+
        gossip_chat_view_append_message (chat->view, message);
 
        if (gossip_chat_should_play_sound (chat)) {
                // FIXME: gossip_sound_play (GOSSIP_SOUND_CHAT);
        }
 
-       g_signal_emit_by_name (chat, "new-message", message, FALSE);
+       g_signal_emit (chat, signals[NEW_MESSAGE], 0, message, FALSE);
 }
 
 void 
@@ -541,7 +558,7 @@ chat_input_key_press_event_cb (GtkWidget   *widget,
        }
 
        /* Catch enter but not ctrl/shift-enter */
-       if (IS_ENTER (event->keyval) && !(event->state & GDK_SHIFT_MASK)) {
+       if (IS_ENTER (event->keyval) && !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) {
                GtkTextView *view;
 
                /* This is to make sure that kinput2 gets the enter. And if
@@ -562,7 +579,7 @@ chat_input_key_press_event_cb (GtkWidget   *widget,
 
        text_view_sw = gtk_widget_get_parent (GTK_WIDGET (chat->view));
 
-       if (IS_ENTER (event->keyval) && (event->state & GDK_SHIFT_MASK)) {
+       if (IS_ENTER (event->keyval) && (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) {
                /* Newline for shift-enter. */
                return FALSE;
        }
@@ -916,10 +933,10 @@ static void
 chat_text_check_word_spelling_cb (GtkMenuItem     *menuitem,
                                  GossipChatSpell *chat_spell)
 {
-/*FIXME:       gossip_spell_dialog_show (chat_spell->chat,
+       gossip_spell_dialog_show (chat_spell->chat,
                                  chat_spell->start,
                                  chat_spell->end,
-                                 chat_spell->word);*/
+                                 chat_spell->word);
 }
 
 static GossipChatSpell *
@@ -1014,7 +1031,127 @@ chat_state_changed_cb (EmpathyTpChat             *tp_chat,
                       TelepathyChannelChatState  state,
                       GossipChat                *chat)
 {
-       /* FIXME: not yet implemented */
+       GossipChatPriv *priv;
+       GList          *l;
+       gboolean        was_composing;
+
+       priv = GET_PRIV (chat);
+
+       if (gossip_contact_is_user (contact)) {
+               /* We don't care about our own chat state */
+               return;
+       }
+
+       was_composing = (priv->compositors != NULL);
+
+       /* Find the contact in the list. After that l is the list elem or NULL */
+       for (l = priv->compositors; l; l = l->next) {
+               if (gossip_contact_equal (contact, l->data)) {
+                       break;
+               }
+       }
+
+       switch (state) {
+       case TP_CHANNEL_CHAT_STATE_GONE:
+       case TP_CHANNEL_CHAT_STATE_INACTIVE:
+       case TP_CHANNEL_CHAT_STATE_ACTIVE:
+               /* Contact is not composing */
+               if (l) {
+                       priv->compositors = g_list_remove_link (priv->compositors, l);
+                       g_object_unref (l->data);
+                       g_list_free1 (l);
+               }
+               break;
+       case TP_CHANNEL_CHAT_STATE_PAUSED:
+       case TP_CHANNEL_CHAT_STATE_COMPOSING:
+               /* Contact is composing */
+               if (!l) {
+                       priv->compositors = g_list_prepend (priv->compositors,
+                                                           g_object_ref (contact));
+               }
+               break;
+       default:
+               g_assert_not_reached ();
+       }
+
+       gossip_debug (DEBUG_DOMAIN, "Was composing: %s now composing: %s",
+                     was_composing ? "yes" : "no",
+                     priv->compositors ? "yes" : "no");
+
+       if ((was_composing && !priv->compositors) ||
+           (!was_composing && priv->compositors)) {
+               /* Composing state changed */
+               g_signal_emit (chat, signals[COMPOSING], 0,
+                              priv->compositors != NULL);
+       }
+}
+
+static void
+chat_add_logs (GossipChat *chat)
+{
+       GossipChatPriv *priv;
+       GList          *messages, *l;
+       guint           num_messages;
+       guint           i;
+
+       priv = GET_PRIV (chat);
+
+       /* Do not display backlog for chatrooms */
+       if (gossip_chat_is_group_chat (chat)) {
+               return;
+       }
+
+       /* Turn off scrolling temporarily */
+       gossip_chat_view_scroll (chat->view, FALSE);
+
+       /* Add messages from last conversation */
+       messages = empathy_log_manager_get_last_messages (priv->log_manager,
+                                                         chat->account,
+                                                         gossip_chat_get_id (chat),
+                                                         gossip_chat_is_group_chat (chat));
+       num_messages  = g_list_length (messages);
+
+       for (l = messages, i = 0; l; l = l->next, i++) {
+               GossipMessage *message;
+
+               message = l->data;
+
+               /* Only add 10 last messages */
+               if (num_messages - i > 10) {
+                       g_object_unref (message);
+                       continue;
+               }
+
+
+               gossip_chat_view_append_message (chat->view, message);
+               g_object_unref (message);
+       }
+       g_list_free (messages);
+
+       /* Turn back on scrolling */
+       gossip_chat_view_scroll (chat->view, TRUE);
+
+       /* Scroll to the most recent messages, we reference the chat
+        * for the duration of the scroll func.
+        */
+       priv->scroll_idle_id = g_idle_add ((GSourceFunc) chat_scroll_down_idle_func, 
+                                          g_object_ref (chat));
+}
+
+/* Scroll down after the back-log has been received. */
+static gboolean
+chat_scroll_down_idle_func (GossipChat *chat)
+{
+       GossipChatPriv *priv;
+
+       priv = GET_PRIV (chat);
+
+       gossip_chat_scroll_down (chat);
+       g_object_unref (chat);
+
+       priv->scroll_idle_id = 0;
+
+       return FALSE;
 }
 
 gboolean
@@ -1094,29 +1231,6 @@ gossip_chat_get_status_icon_name (GossipChat *chat)
        return NULL;
 }
 
-GossipContact *
-gossip_chat_get_contact (GossipChat *chat)
-{
-       g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL);
-
-       if (GOSSIP_CHAT_GET_CLASS (chat)->get_contact) {
-               return GOSSIP_CHAT_GET_CLASS (chat)->get_contact (chat);
-       }
-
-       return NULL;
-}
-GossipContact *
-gossip_chat_get_own_contact (GossipChat *chat)
-{
-       GossipChatPriv *priv;
-
-       g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL);
-
-       priv = GET_PRIV (chat);
-
-       return empathy_contact_manager_get_own (priv->manager, chat->account);
-}
-
 GtkWidget *
 gossip_chat_get_widget (GossipChat *chat)
 {
@@ -1153,29 +1267,6 @@ gossip_chat_is_connected (GossipChat *chat)
        return (priv->tp_chat != NULL);
 }
 
-gboolean
-gossip_chat_get_show_contacts (GossipChat *chat)
-{
-       g_return_val_if_fail (GOSSIP_IS_CHAT (chat), FALSE);
-
-       if (GOSSIP_CHAT_GET_CLASS (chat)->get_show_contacts) {
-               return GOSSIP_CHAT_GET_CLASS (chat)->get_show_contacts (chat);
-       }
-
-       return FALSE;
-}
-
-void
-gossip_chat_set_show_contacts (GossipChat *chat,
-                              gboolean    show)
-{
-       g_return_if_fail (GOSSIP_IS_CHAT (chat));
-
-       if (GOSSIP_CHAT_GET_CLASS (chat)->set_show_contacts) {
-               GOSSIP_CHAT_GET_CLASS (chat)->set_show_contacts (chat, show);
-       }
-}
-
 void
 gossip_chat_save_geometry (GossipChat *chat,
                           gint        x,
@@ -1201,7 +1292,6 @@ gossip_chat_set_tp_chat (GossipChat    *chat,
                         EmpathyTpChat *tp_chat)
 {
        GossipChatPriv *priv;
-       GtkWidget      *widget;
 
        g_return_if_fail (GOSSIP_IS_CHAT (chat));
        g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat));
@@ -1225,6 +1315,12 @@ gossip_chat_set_tp_chat (GossipChat    *chat,
        g_free (priv->id);
        priv->tp_chat = g_object_ref (tp_chat);
        priv->id = g_strdup (empathy_tp_chat_get_id (tp_chat));
+       priv->time_joined = gossip_time_get_current ();
+
+       if (priv->first_tp_chat) {
+               chat_add_logs (chat);
+               priv->first_tp_chat = FALSE;
+       }
 
        g_signal_connect (tp_chat, "message-received",
                          G_CALLBACK (chat_message_received_cb),
@@ -1239,11 +1335,15 @@ gossip_chat_set_tp_chat (GossipChat    *chat,
        empathy_tp_chat_request_pending (tp_chat);
 
        if (!priv->sensitive) {
-               widget = gossip_chat_get_widget (chat);
-               gtk_widget_set_sensitive (widget, TRUE);
+               gtk_widget_set_sensitive (chat->input_text_view, TRUE);
                gossip_chat_view_append_event (chat->view, _("Connected"));
                priv->sensitive = TRUE;
        }
+
+       if (GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat) {
+               GOSSIP_CHAT_GET_CLASS (chat)->set_tp_chat (chat, tp_chat);
+       }
+
 }
 
 const gchar *
@@ -1394,7 +1494,7 @@ gossip_chat_should_play_sound (GossipChat *chat)
 gboolean
 gossip_chat_should_highlight_nick (GossipMessage *message)
 {
-       GossipContact *my_contact;
+       GossipContact *contact;
        const gchar   *msg, *to;
        gchar         *cf_msg, *cf_to;
        gchar         *ch;
@@ -1411,8 +1511,12 @@ gossip_chat_should_highlight_nick (GossipMessage *message)
                return FALSE;
        }
 
-       my_contact = gossip_get_own_contact_from_contact (gossip_message_get_sender (message));
-       to = gossip_contact_get_name (my_contact);
+       contact = gossip_message_get_receiver (message);
+       if (!contact || !gossip_contact_is_user (contact)) {
+               return FALSE;
+       }
+
+       to = gossip_contact_get_name (contact);
        if (!to) {
                return FALSE;
        }