aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'libempathy-gtk')
-rw-r--r--libempathy-gtk/empathy-chat.c301
1 files changed, 251 insertions, 50 deletions
diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c
index 7984b8a3a..b2fefee5f 100644
--- a/libempathy-gtk/empathy-chat.c
+++ b/libempathy-gtk/empathy-chat.c
@@ -73,8 +73,8 @@ typedef struct {
EmpathyLogManager *log_manager;
TpAccountManager *account_manager;
- GSList *sent_messages;
- gint sent_messages_index;
+ GList *input_history;
+ GList *input_history_current;
GList *compositors;
GCompletion *completion;
guint composing_stop_timeout_id;
@@ -94,6 +94,13 @@ typedef struct {
GtkWidget *contact_list_view;
} EmpathyChatPriv;
+typedef struct {
+ gchar *text; /* Original message that was specified
+ * upon entry creation. */
+ gchar *modified_text; /* Message that was modified by user.
+ * When no modifications were made, it is NULL */
+} InputHistoryEntry;
+
enum {
COMPOSING,
NEW_MESSAGE,
@@ -295,89 +302,280 @@ chat_composing_stop (EmpathyChat *chat)
TP_CHANNEL_CHAT_STATE_ACTIVE);
}
+static gint
+chat_input_history_entry_cmp (InputHistoryEntry *entry,
+ const gchar *text)
+{
+ if (!tp_strdiff (entry->text, text)) {
+ if (entry->modified_text != NULL) {
+ /* Modified entry and single string cannot be equal. */
+ return 1;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static InputHistoryEntry *
+chat_input_history_entry_new_with_text (const gchar *text)
+{
+ InputHistoryEntry *entry;
+ entry = g_slice_new0 (InputHistoryEntry);
+ entry->text = g_strdup (text);
+
+ return entry;
+}
+
static void
-chat_sent_message_add (EmpathyChat *chat,
- const gchar *str)
+chat_input_history_entry_free (InputHistoryEntry *entry)
{
- EmpathyChatPriv *priv;
- GSList *list;
- GSList *item;
+ g_free (entry->text);
+ g_free (entry->modified_text);
+ g_slice_free (InputHistoryEntry, entry);
+}
+
+static void
+chat_input_history_entry_revert (InputHistoryEntry *entry)
+{
+ g_free (entry->modified_text);
+ entry->modified_text = NULL;
+}
+
+static void
+chat_input_history_entry_update_text (InputHistoryEntry *entry,
+ const gchar *text)
+{
+ gchar *old;
+
+ if (!tp_strdiff (text, entry->text)) {
+ g_free (entry->modified_text);
+ entry->modified_text = NULL;
+ return;
+ }
+
+ old = entry->modified_text;
+ entry->modified_text = g_strdup (text);
+ g_free (old);
+}
+
+static const gchar *
+chat_input_history_entry_get_text (InputHistoryEntry *entry)
+{
+ if (entry == NULL) {
+ return NULL;
+ }
+
+ if (entry->modified_text != NULL) {
+ return entry->modified_text;
+ }
+ return entry->text;
+}
+
+static GList *
+chat_input_history_remove_item (GList *list,
+ GList *item)
+{
+ list = g_list_remove_link (list, item);
+ chat_input_history_entry_free (item->data);
+ g_list_free_1 (item);
+ return list;
+}
+
+static void
+chat_input_history_revert (EmpathyChat *chat)
+{
+ EmpathyChatPriv *priv;
+ GList *list;
+ GList *item1;
+ GList *item2;
+ InputHistoryEntry *entry;
priv = GET_PRIV (chat);
+ list = priv->input_history;
+
+ if (list == NULL) {
+ DEBUG ("No input history");
+ return;
+ }
- /* Save the sent message in our repeat buffer */
- list = priv->sent_messages;
+ /* Delete temporary entry */
+ if (priv->input_history_current != NULL) {
+ item1 = list;
+ list = chat_input_history_remove_item (list, item1);
+ if (priv->input_history_current == item1) {
+ /* Removed temporary entry was current entry */
+ priv->input_history = list;
+ priv->input_history_current = NULL;
+ return;
+ }
+ }
+ else {
+ /* There is no entry to revert */
+ return;
+ }
- /* 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);
+ /* Restore the current history entry to original value */
+ item1 = priv->input_history_current;
+ entry = item1->data;
+ chat_input_history_entry_revert (entry);
+
+ /* Remove restored entry if there is other occurance before this entry */
+ item2 = g_list_find_custom (list, chat_input_history_entry_get_text (entry),
+ (GCompareFunc) chat_input_history_entry_cmp);
+ if (item2 != item1) {
+ list = chat_input_history_remove_item (list, item1);
+ }
+ else {
+ /* Remove other occurance of the restored entry */
+ item2 = g_list_find_custom (item1->next,
+ chat_input_history_entry_get_text (entry),
+ (GCompareFunc) chat_input_history_entry_cmp);
+ if (item2 != NULL) {
+ list = chat_input_history_remove_item (list, item2);
+ }
}
- /* 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);
+ priv->input_history_current = NULL;
+ priv->input_history = list;
+}
+
+static void
+chat_input_history_add (EmpathyChat *chat,
+ const gchar *str,
+ gboolean temporary)
+{
+ EmpathyChatPriv *priv;
+ GList *list;
+ GList *item;
+ InputHistoryEntry *entry;
+
+ priv = GET_PRIV (chat);
+
+ list = priv->input_history;
+
+ /* Remove any other occurances of this entry, if not temporary */
+ if (!temporary) {
+ while ((item = g_list_find_custom (list, str,
+ (GCompareFunc) chat_input_history_entry_cmp)) != NULL) {
+ list = chat_input_history_remove_item (list, item);
+ }
+
+ /* Trim the list to the last 10 items */
+ while (g_list_length (list) > 10) {
+ item = g_list_last (list);
+ if (item != NULL) {
+ list = chat_input_history_remove_item (list, 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;
+
+ /* Add new entry */
+ entry = chat_input_history_entry_new_with_text (str);
+ list = g_list_prepend (list, entry);
+
+ /* Set the list and the current item pointer */
+ priv->input_history = list;
+ if (temporary) {
+ priv->input_history_current = list;
+ }
+ else {
+ priv->input_history_current = NULL;
+ }
}
static const gchar *
-chat_sent_message_get_next (EmpathyChat *chat)
+chat_input_history_get_next (EmpathyChat *chat)
{
EmpathyChatPriv *priv;
- gint max;
+ GList *item;
+ const gchar *msg;
priv = GET_PRIV (chat);
- if (!priv->sent_messages) {
- DEBUG ("No sent messages, next message is NULL");
+ if (priv->input_history == NULL) {
+ DEBUG ("No input history, next entry is NULL");
return NULL;
}
+ g_assert (priv->input_history_current != NULL);
- max = g_slist_length (priv->sent_messages) - 1;
-
- if (priv->sent_messages_index < max) {
- priv->sent_messages_index++;
+ if ((item = g_list_next (priv->input_history_current)) == NULL)
+ {
+ item = priv->input_history_current;
}
- DEBUG ("Returning next message index:%d", priv->sent_messages_index);
+ msg = chat_input_history_entry_get_text (item->data);
- return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
+ DEBUG ("Returning next entry: '%s'", msg);
+
+ priv->input_history_current = item;
+
+ return msg;
}
static const gchar *
-chat_sent_message_get_last (EmpathyChat *chat)
+chat_input_history_get_prev (EmpathyChat *chat)
{
EmpathyChatPriv *priv;
+ GList *item;
+ const gchar *msg;
g_return_val_if_fail (EMPATHY_IS_CHAT (chat), NULL);
priv = GET_PRIV (chat);
- if (!priv->sent_messages) {
- DEBUG ("No sent messages, last message is NULL");
+ if (priv->input_history == NULL) {
+ DEBUG ("No input history, previous entry is NULL");
return NULL;
}
- if (priv->sent_messages_index >= 0) {
- priv->sent_messages_index--;
+ if (priv->input_history_current == NULL)
+ {
+ return NULL;
}
+ else if ((item = g_list_previous (priv->input_history_current)) == NULL)
+ {
+ item = priv->input_history_current;
+ }
+
+ msg = chat_input_history_entry_get_text (item->data);
+
+ DEBUG ("Returning previous entry: '%s'", msg);
- DEBUG ("Returning last message index:%d", priv->sent_messages_index);
+ priv->input_history_current = item;
+
+ return msg;
+}
+
+static void
+chat_input_history_update (EmpathyChat *chat,
+ GtkTextBuffer *buffer)
+{
+ EmpathyChatPriv *priv;
+ GtkTextIter start, end;
+ gchar *text;
+ InputHistoryEntry *entry;
+
+ priv = GET_PRIV (chat);
+
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+
+ if (priv->input_history_current == NULL) {
+ /* Add the current text temporarily to the history */
+ chat_input_history_add (chat, text, TRUE);
+ g_free (text);
+ return;
+ }
+
+ /* Save the changes in the history */
+ entry = priv->input_history_current->data;
+ if (tp_strdiff (chat_input_history_entry_get_text (entry), text)) {
+ chat_input_history_entry_update_text (entry, text);
+ }
- return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
+ g_free (text);
}
static void
@@ -393,7 +591,7 @@ chat_send (EmpathyChat *chat,
priv = GET_PRIV (chat);
- chat_sent_message_add (chat, msg);
+ chat_input_history_add (chat, msg, FALSE);
if (strcmp (msg, "/clear") == 0) {
empathy_chat_view_clear (chat->view);
@@ -428,6 +626,8 @@ chat_input_text_view_send (EmpathyChat *chat)
/* clear the input field */
gtk_text_buffer_set_text (buffer, "", -1);
+ /* delete input history modifications */
+ chat_input_history_revert (chat);
chat_send (chat, msg);
g_free (msg);
@@ -699,11 +899,12 @@ chat_input_key_press_event_cb (GtkWidget *widget,
const gchar *str;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (chat->input_text_view));
+ chat_input_history_update (chat, buffer);
if (event->keyval == GDK_Up) {
- str = chat_sent_message_get_next (chat);
+ str = chat_input_history_get_next (chat);
} else {
- str = chat_sent_message_get_last (chat);
+ str = chat_input_history_get_prev (chat);
}
g_signal_handlers_block_by_func (buffer,
@@ -1536,8 +1737,8 @@ chat_finalize (GObject *object)
DEBUG ("Finalized: %p", object);
- g_slist_foreach (priv->sent_messages, (GFunc) g_free, NULL);
- g_slist_free (priv->sent_messages);
+ g_list_foreach (priv->input_history, (GFunc) chat_input_history_entry_free, NULL);
+ g_list_free (priv->input_history);
g_list_foreach (priv->compositors, (GFunc) g_object_unref, NULL);
g_list_free (priv->compositors);
@@ -1736,8 +1937,8 @@ empathy_chat_init (EmpathyChat *chat)
chat->priv = priv;
priv->log_manager = empathy_log_manager_dup_singleton ();
priv->contacts_width = -1;
- priv->sent_messages = NULL;
- priv->sent_messages_index = -1;
+ priv->input_history = NULL;
+ priv->input_history_current = NULL;
priv->account_manager = tp_account_manager_dup ();
tp_account_manager_prepare_async (priv->account_manager, NULL,