]> git.0d.be Git - empathy.git/blobdiff - libempathy-gtk/gossip-chat.c
[darcs-to-svn @ after a timeout we are in PAUSED chat state]
[empathy.git] / libempathy-gtk / gossip-chat.c
index 616b3abe3057e0fdaa1d5150bcbb3fe552b556c5..614abd7d78dcd9ee579ec30ebfe8f00ef288c757 100644 (file)
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * Copyright (C) 2002-2007 Imendio AB
+ * Copyright (C) 2007 Collabora Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -21,6 +22,7 @@
  *          Richard Hult <richard@imendio.com>
  *          Martyn Russell <martyn@imendio.com>
  *          Geert-Jan Van den Bogaerde <geertjan@gnome.org>
+ *          Xavier Claessens <xclaesse@gmail.com>
  */
 
 #include "config.h"
@@ -33,7 +35,6 @@
 #include <gtk/gtk.h>
 #include <glade/glade.h>
 
-#include <libempathy/empathy-session.h>
 #include <libempathy/empathy-contact-manager.h>
 #include <libempathy/gossip-debug.h>
 #include <libempathy/gossip-utils.h>
@@ -41,7 +42,7 @@
 
 #include "gossip-chat.h"
 #include "gossip-chat-window.h"
-//#include "gossip-geometry.h"
+#include "gossip-geometry.h"
 #include "gossip-preferences.h"
 #include "gossip-spell.h"
 //#include "gossip-spell-dialog.h"
 #define COMPOSING_STOP_TIMEOUT 5
 
 struct _GossipChatPriv {
-       EmpathyTpChat    *tp_chat;
-       GossipChatWindow *window;
-
-       GtkTooltips      *tooltips;
-       guint             composing_stop_timeout_id;
-       gboolean          sensitive;
+       EmpathyContactManager *manager;
+       EmpathyTpChat         *tp_chat;
+       GossipChatWindow      *window;
+
+       GtkTooltips           *tooltips;
+       guint                  composing_stop_timeout_id;
+       gboolean               sensitive;
+       gchar                 *id;
+       GSList                *sent_messages;
+       gint                   sent_messages_index;
        /* Used to automatically shrink a window that has temporarily
         * grown due to long input. 
         */
-       gint              padding_height;
-       gint              default_window_height;
-       gint              last_input_height;
-       gboolean          vscroll_visible;
+       gint                   padding_height;
+       gint                   default_window_height;
+       gint                   last_input_height;
+       gboolean               vscroll_visible;
 };
 
 typedef struct {
@@ -95,6 +100,10 @@ static void             chat_input_text_view_send         (GossipChat      *chat
 static void             chat_message_received_cb          (EmpathyTpChat   *tp_chat,
                                                           GossipMessage   *message,
                                                           GossipChat      *chat);
+void                    chat_sent_message_add             (GossipChat      *chat,
+                                                          const gchar     *str);
+const gchar *           chat_sent_message_get_next        (GossipChat      *chat);
+const gchar *           chat_sent_message_get_last        (GossipChat      *chat);
 static gboolean         chat_input_key_press_event_cb     (GtkWidget       *widget,
                                                           GdkEventKey     *event,
                                                           GossipChat      *chat);
@@ -124,6 +133,10 @@ static void             chat_composing_start              (GossipChat      *chat
 static void             chat_composing_stop               (GossipChat      *chat);
 static void             chat_composing_remove_timeout     (GossipChat      *chat);
 static gboolean         chat_composing_stop_timeout_cb    (GossipChat      *chat);
+static void             chat_state_changed_cb             (EmpathyTpChat   *tp_chat,
+                                                          GossipContact   *contact,
+                                                          TelepathyChannelChatState  state,
+                                                          GossipChat      *chat);
 
 enum {
        COMPOSING,
@@ -211,11 +224,13 @@ gossip_chat_init (GossipChat *chat)
 
        priv = GET_PRIV (chat);
 
+       priv->manager = empathy_contact_manager_new ();
        priv->tooltips = gtk_tooltips_new ();
-
        priv->default_window_height = -1;
        priv->vscroll_visible = FALSE;
        priv->sensitive = TRUE;
+       priv->sent_messages = NULL;
+       priv->sent_messages_index = -1;
 
        g_signal_connect (chat->input_text_view,
                          "key_press_event",
@@ -227,7 +242,7 @@ gossip_chat_init (GossipChat *chat)
                          "changed",
                          G_CALLBACK (chat_input_text_buffer_changed_cb),
                          chat);
-       g_signal_connect (GOSSIP_CHAT (chat)->view,
+       g_signal_connect (chat->view,
                          "focus_in_event",
                          G_CALLBACK (chat_text_view_focus_in_event_cb),
                          chat);
@@ -265,13 +280,19 @@ chat_finalize (GObject *object)
 
        gossip_debug (DEBUG_DOMAIN, "Finalized: %p", object);
 
+       g_slist_foreach (priv->sent_messages, (GFunc) g_free, NULL);
+       g_slist_free (priv->sent_messages);
+
        chat_composing_remove_timeout (chat);
-       g_object_unref (GOSSIP_CHAT (object)->account);
+       g_object_unref (chat->account);
+       g_object_unref (priv->manager);
 
        if (priv->tp_chat) {
                g_object_unref (priv->tp_chat);
        }
 
+       g_free (priv->id);
+
        G_OBJECT_CLASS (gossip_chat_parent_class)->finalize (object);
 }
 
@@ -307,10 +328,12 @@ chat_send (GossipChat  *chat,
 
        priv = GET_PRIV (chat);
 
-       if (msg == NULL || msg[0] == '\0') {
+       if (G_STR_EMPTY (msg)) {
                return;
        }
 
+       chat_sent_message_add (chat, msg);
+
        if (g_str_has_prefix (msg, "/clear")) {
                gossip_chat_view_clear (chat->view);
                return;
@@ -383,6 +406,97 @@ chat_message_received_cb (EmpathyTpChat *tp_chat,
        g_signal_emit_by_name (chat, "new-message", message);
 }
 
+void 
+chat_sent_message_add (GossipChat  *chat,
+                      const gchar *str)
+{
+       GossipChatPriv *priv;
+       GSList         *list;
+       GSList         *item;
+
+       priv = GET_PRIV (chat);
+
+       /* Save the sent message in our repeat buffer */
+       list = priv->sent_messages;
+       
+       /* Remove any other occurances of this msg */
+       while ((item = g_slist_find_custom (list, str, (GCompareFunc) strcmp)) != NULL) {
+               list = g_slist_remove_link (list, item);
+               g_free (item->data);
+               g_slist_free1 (item);
+       }
+
+       /* Trim the list to the last 10 items */
+       while (g_slist_length (list) > 10) {
+               item = g_slist_last (list);
+               if (item) {
+                       list = g_slist_remove_link (list, item);
+                       g_free (item->data);
+                       g_slist_free1 (item);
+               }
+       }
+
+       /* Add new message */
+       list = g_slist_prepend (list, g_strdup (str));
+
+       /* Set list and reset the index */
+       priv->sent_messages = list;
+       priv->sent_messages_index = -1;
+}
+
+const gchar *
+chat_sent_message_get_next (GossipChat *chat)
+{
+       GossipChatPriv *priv;
+       gint            max;
+       
+       priv = GET_PRIV (chat);
+
+       if (!priv->sent_messages) {
+               gossip_debug (DEBUG_DOMAIN, 
+                             "No sent messages, next message is NULL");
+               return NULL;
+       }
+
+       max = g_slist_length (priv->sent_messages) - 1;
+
+       if (priv->sent_messages_index < max) {
+               priv->sent_messages_index++;
+       }
+       
+       gossip_debug (DEBUG_DOMAIN, 
+                     "Returning next message index:%d",
+                     priv->sent_messages_index);
+
+       return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
+}
+
+const gchar *
+chat_sent_message_get_last (GossipChat *chat)
+{
+       GossipChatPriv *priv;
+
+       g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL);
+
+       priv = GET_PRIV (chat);
+       
+       if (!priv->sent_messages) {
+               gossip_debug (DEBUG_DOMAIN, 
+                             "No sent messages, last message is NULL");
+               return NULL;
+       }
+
+       if (priv->sent_messages_index >= 0) {
+               priv->sent_messages_index--;
+       }
+
+       gossip_debug (DEBUG_DOMAIN, 
+                     "Returning last message index:%d",
+                     priv->sent_messages_index);
+
+       return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
+}
+
 static gboolean
 chat_input_key_press_event_cb (GtkWidget   *widget,
                               GdkEventKey *event,
@@ -399,6 +513,32 @@ chat_input_key_press_event_cb (GtkWidget   *widget,
                return TRUE;
        }
 
+       /* Catch ctrl+up/down so we can traverse messages we sent */
+       if ((event->state & GDK_CONTROL_MASK) && 
+           (event->keyval == GDK_Up || 
+            event->keyval == GDK_Down)) {
+               GtkTextBuffer *buffer;
+               const gchar   *str;
+
+               buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
+
+               if (event->keyval == GDK_Up) {
+                       str = chat_sent_message_get_next (chat);
+               } else {
+                       str = chat_sent_message_get_last (chat);
+               }
+
+               g_signal_handlers_block_by_func (buffer, 
+                                                chat_input_text_buffer_changed_cb,
+                                                chat);
+               gtk_text_buffer_set_text (buffer, str ? str : "", -1);
+               g_signal_handlers_unblock_by_func (buffer, 
+                                                  chat_input_text_buffer_changed_cb,
+                                                  chat);
+
+               return TRUE;    
+       }
+
        /* Catch enter but not ctrl/shift-enter */
        if (IS_ENTER (event->keyval) && !(event->state & GDK_SHIFT_MASK)) {
                GtkTextView *view;
@@ -420,6 +560,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)) {
                /* Newline for shift-enter. */
                return FALSE;
@@ -817,10 +958,8 @@ chat_composing_start (GossipChat *chat)
                /* Just restart the timeout */
                chat_composing_remove_timeout (chat);
        } else {
-       /* FIXME:
-               gossip_session_send_composing (gossip_app_get_session (),
-                                              priv->contact, TRUE);
-                                             */
+               empathy_tp_chat_set_state (priv->tp_chat,
+                                          TP_CHANNEL_CHAT_STATE_COMPOSING);
        }
 
        priv->composing_stop_timeout_id = g_timeout_add (
@@ -837,9 +976,8 @@ chat_composing_stop (GossipChat *chat)
        priv = GET_PRIV (chat);
 
        chat_composing_remove_timeout (chat);
-       /* FIXME:
-       gossip_session_send_composing (gossip_app_get_session (),
-                                      priv->contact, FALSE);*/
+       empathy_tp_chat_set_state (priv->tp_chat,
+                                  TP_CHANNEL_CHAT_STATE_ACTIVE);
 }
 
 static void
@@ -863,13 +1001,21 @@ chat_composing_stop_timeout_cb (GossipChat *chat)
        priv = GET_PRIV (chat);
 
        priv->composing_stop_timeout_id = 0;
-       /* FIXME:
-       gossip_session_send_composing (gossip_app_get_session (),
-                                      priv->contact, FALSE);*/
+       empathy_tp_chat_set_state (priv->tp_chat,
+                                  TP_CHANNEL_CHAT_STATE_PAUSED);
 
        return FALSE;
 }
 
+static void
+chat_state_changed_cb (EmpathyTpChat             *tp_chat,
+                      GossipContact             *contact,
+                      TelepathyChannelChatState  state,
+                      GossipChat                *chat)
+{
+       /* FIXME: not yet implemented */
+}
+
 gboolean
 gossip_chat_get_is_command (const gchar *str)
 {
@@ -935,13 +1081,13 @@ gossip_chat_get_tooltip (GossipChat *chat)
        return NULL;
 }
 
-GdkPixbuf *
-gossip_chat_get_status_pixbuf (GossipChat *chat)
+const gchar *
+gossip_chat_get_status_icon_name (GossipChat *chat)
 {
        g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL);
 
-       if (GOSSIP_CHAT_GET_CLASS (chat)->get_status_pixbuf) {
-               return GOSSIP_CHAT_GET_CLASS (chat)->get_status_pixbuf (chat);
+       if (GOSSIP_CHAT_GET_CLASS (chat)->get_status_icon_name) {
+               return GOSSIP_CHAT_GET_CLASS (chat)->get_status_icon_name (chat);
        }
 
        return NULL;
@@ -961,13 +1107,13 @@ gossip_chat_get_contact (GossipChat *chat)
 GossipContact *
 gossip_chat_get_own_contact (GossipChat *chat)
 {
-       EmpathyContactManager *manager;
+       GossipChatPriv *priv;
 
        g_return_val_if_fail (GOSSIP_IS_CHAT (chat), NULL);
 
-       manager = empathy_session_get_contact_manager ();
+       priv = GET_PRIV (chat);
 
-       return empathy_contact_manager_get_own (manager, chat->account);
+       return empathy_contact_manager_get_own (priv->manager, chat->account);
 }
 
 GtkWidget *
@@ -1036,7 +1182,7 @@ gossip_chat_save_geometry (GossipChat *chat,
                           gint        w,
                           gint        h)
 {
-       //FIXME: gossip_geometry_save_for_chat (chat, x, y, w, h);
+       gossip_geometry_save (gossip_chat_get_id (chat), x, y, w, h);
 }
 
 void
@@ -1046,7 +1192,7 @@ gossip_chat_load_geometry (GossipChat *chat,
                           gint       *w,
                           gint       *h)
 {
-       //FIXME: gossip_geometry_load_for_chat (chat, x, y, w, h);
+       gossip_geometry_load (gossip_chat_get_id (chat), x, y, w, h);
 }
 
 void
@@ -1075,11 +1221,16 @@ gossip_chat_set_tp_chat (GossipChat    *chat,
                g_object_unref (priv->tp_chat);
        }
 
+       g_free (priv->id);
        priv->tp_chat = g_object_ref (tp_chat);
+       priv->id = g_strdup (empathy_tp_chat_get_id (tp_chat));
 
        g_signal_connect (tp_chat, "message-received",
                          G_CALLBACK (chat_message_received_cb),
                          chat);
+       g_signal_connect (tp_chat, "chat-state-changed",
+                         G_CALLBACK (chat_state_changed_cb),
+                         chat);
        g_signal_connect (tp_chat, "destroy",
                          G_CALLBACK (chat_destroy_cb),
                          chat);
@@ -1094,6 +1245,16 @@ gossip_chat_set_tp_chat (GossipChat    *chat,
        }
 }
 
+const gchar *
+gossip_chat_get_id (GossipChat *chat)
+{
+       GossipChatPriv *priv;
+
+       priv = GET_PRIV (chat);
+
+       return priv->id;
+}
+
 void
 gossip_chat_clear (GossipChat *chat)
 {
@@ -1219,7 +1380,7 @@ gossip_chat_should_play_sound (GossipChat *chat)
 
        g_return_val_if_fail (GOSSIP_IS_CHAT (chat), FALSE);
 
-       window = gossip_chat_get_window (GOSSIP_CHAT (chat));
+       window = gossip_chat_get_window (chat);
        if (!window) {
                return TRUE;
        }