diff options
Diffstat (limited to 'libempathy-gtk/empathy-chat.c')
-rw-r--r-- | libempathy-gtk/empathy-chat.c | 369 |
1 files changed, 297 insertions, 72 deletions
diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index cfeb0073b..e96c02db2 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -34,9 +34,9 @@ #include <glib/gi18n-lib.h> #include <gtk/gtk.h> +#include <telepathy-glib/account-manager.h> #include <telepathy-glib/util.h> -#include <libempathy/empathy-account-manager.h> #include <libempathy/empathy-log-manager.h> #include <libempathy/empathy-contact-list.h> #include <libempathy/empathy-utils.h> @@ -64,7 +64,7 @@ #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChat) typedef struct { EmpathyTpChat *tp_chat; - EmpathyAccount *account; + TpAccount *account; gchar *id; gchar *name; gchar *subject; @@ -72,9 +72,9 @@ typedef struct { gboolean show_contacts; EmpathyLogManager *log_manager; - EmpathyAccountManager *account_manager; - GSList *sent_messages; - gint sent_messages_index; + TpAccountManager *account_manager; + 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, @@ -196,15 +203,19 @@ chat_connect_channel_reconnected (EmpathyDispatchOperation *dispatch, } static void -chat_new_connection_cb (EmpathyAccountManager *manager, - TpConnection *connection, +chat_new_connection_cb (TpAccount *account, + guint old_status, + guint new_status, + guint reason, + gchar *dbus_error_name, + GHashTable *details, EmpathyChat *chat) { EmpathyChatPriv *priv = GET_PRIV (chat); - EmpathyAccount *account; + TpConnection *connection; + + connection = tp_account_get_connection (account); - account = empathy_account_manager_get_account_for_connection (manager, - connection); if (!priv->tp_chat && account == priv->account && priv->handle_type != TP_HANDLE_TYPE_NONE && !EMP_STR_EMPTY (priv->id)) { @@ -291,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; - /* Save the sent message in our repeat buffer */ - list = priv->sent_messages; + if (list == NULL) { + DEBUG ("No input history"); + 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); + /* 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; } - /* 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); + /* 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); } } - /* Add new message */ - list = g_slist_prepend (list, g_strdup (str)); + priv->input_history_current = NULL; + priv->input_history = list; +} - /* Set list and reset the index */ - priv->sent_messages = list; - priv->sent_messages_index = -1; +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 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); + + DEBUG ("Returning next entry: '%s'", msg); - return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index); + 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; } - DEBUG ("Returning last 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 previous entry: '%s'", msg); + + 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); + } + + g_free (text); } static void @@ -680,7 +882,7 @@ chat_send (EmpathyChat *chat, priv = GET_PRIV (chat); - chat_sent_message_add (chat, msg); + chat_input_history_add (chat, msg, FALSE); if (msg[0] == '/') { gboolean second_slash = FALSE; @@ -754,6 +956,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); @@ -1025,11 +1229,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, @@ -1859,17 +2064,14 @@ 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); chat_composing_remove_timeout (chat); - g_signal_handlers_disconnect_by_func (priv->account_manager, - chat_new_connection_cb, object); - g_object_unref (priv->account_manager); g_object_unref (priv->log_manager); @@ -1947,7 +2149,7 @@ empathy_chat_class_init (EmpathyChatClass *klass) g_param_spec_object ("account", "Account of the chat", "The account of the chat", - EMPATHY_TYPE_ACCOUNT, + TP_TYPE_ACCOUNT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, @@ -2025,6 +2227,34 @@ chat_block_events_timeout_cb (gpointer data) } static void +account_manager_prepared_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + GList *accounts, *l; + TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object); + EmpathyChat *chat = user_data; + GError *error = NULL; + + if (!tp_account_manager_prepare_finish (account_manager, result, &error)) { + DEBUG ("Failed to prepare the account manager: %s", error->message); + g_error_free (error); + return; + } + + accounts = tp_account_manager_get_valid_accounts (account_manager); + + for (l = accounts; l != NULL; l = l->next) { + TpAccount *account = l->data; + empathy_signal_connect_weak (account, "status-changed", + G_CALLBACK (chat_new_connection_cb), + G_OBJECT (chat)); + } + + g_list_free (accounts); +} + +static void empathy_chat_init (EmpathyChat *chat) { EmpathyChatPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chat, @@ -2033,14 +2263,12 @@ 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->account_manager = empathy_account_manager_dup_singleton (); + priv->input_history = NULL; + priv->input_history_current = NULL; + priv->account_manager = tp_account_manager_dup (); - g_signal_connect (priv->account_manager, - "new-connection", - G_CALLBACK (chat_new_connection_cb), - chat); + tp_account_manager_prepare_async (priv->account_manager, NULL, + account_manager_prepared_cb, chat); empathy_conf_get_bool (empathy_conf_get (), EMPATHY_PREFS_CHAT_SHOW_CONTACTS_IN_ROOMS, @@ -2096,10 +2324,7 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, priv->tp_chat = g_object_ref (tp_chat); connection = empathy_tp_chat_get_connection (priv->tp_chat); - priv->account = empathy_account_manager_get_account_for_connection ( - priv->account_manager, - connection); - g_object_ref (priv->account); + priv->account = g_object_ref (empathy_get_account_for_connection (connection)); g_signal_connect (tp_chat, "destroy", G_CALLBACK (chat_destroy_cb), @@ -2161,7 +2386,7 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, show_pending_messages (chat); } -EmpathyAccount * +TpAccount * empathy_chat_get_account (EmpathyChat *chat) { EmpathyChatPriv *priv = GET_PRIV (chat); |