/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2006-2007 Imendio AB * Copyright (C) 2007-2008 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 * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA * * Authors: Martyn Russell * Xavier Claessens */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "empathy-log-window.h" #include "empathy-account-chooser.h" #include "empathy-chat-view.h" #include "empathy-theme-manager.h" #include "empathy-ui-utils.h" #define DEBUG_FLAG EMPATHY_DEBUG_OTHER #include typedef struct { GtkWidget *window; GtkWidget *notebook; GtkWidget *entry_find; GtkWidget *button_find; GtkWidget *treeview_find; GtkWidget *scrolledwindow_find; EmpathyChatView *chatview_find; GtkWidget *button_previous; GtkWidget *button_next; GtkWidget *vbox_chats; GtkWidget *account_chooser_chats; GtkWidget *entry_chats; GtkWidget *calendar_chats; GtkWidget *treeview_chats; GtkWidget *scrolledwindow_chats; EmpathyChatView *chatview_chats; gchar *last_find; TplLogManager *log_manager; /* Those are only used while waiting for the account chooser to be ready */ TpAccount *selected_account; gchar *selected_chat_id; gboolean selected_is_chatroom; } EmpathyLogWindow; static void log_window_destroy_cb (GtkWidget *widget, EmpathyLogWindow *window); static void log_window_entry_find_changed_cb (GtkWidget *entry, EmpathyLogWindow *window); static void log_window_find_changed_cb (GtkTreeSelection *selection, EmpathyLogWindow *window); static void log_window_find_populate (EmpathyLogWindow *window, const gchar *search_criteria); static void log_window_find_setup (EmpathyLogWindow *window); static void log_window_button_find_clicked_cb (GtkWidget *widget, EmpathyLogWindow *window); static void log_window_entry_find_activate_cb (GtkWidget *widget, EmpathyLogWindow *window); static void log_window_button_next_clicked_cb (GtkWidget *widget, EmpathyLogWindow *window); static void log_window_button_previous_clicked_cb (GtkWidget *widget, EmpathyLogWindow *window); static void log_window_chats_changed_cb (GtkTreeSelection *selection, EmpathyLogWindow *window); static void log_window_chats_populate (EmpathyLogWindow *window); static void log_window_chats_setup (EmpathyLogWindow *window); static void log_window_chats_accounts_changed_cb (GtkWidget *combobox, EmpathyLogWindow *window); static void log_window_chats_set_selected (EmpathyLogWindow *window); static gboolean log_window_chats_get_selected (EmpathyLogWindow *window, TpAccount **account, gchar **chat_id, gboolean *is_chatroom); static void log_window_chats_get_messages (EmpathyLogWindow *window, GDate *date_to_show); static void log_window_calendar_chats_day_selected_cb (GtkWidget *calendar, EmpathyLogWindow *window); static void log_window_calendar_chats_month_changed_cb (GtkWidget *calendar, EmpathyLogWindow *window); static void log_window_entry_chats_changed_cb (GtkWidget *entry, EmpathyLogWindow *window); static void log_window_entry_chats_activate_cb (GtkWidget *entry, EmpathyLogWindow *window); enum { COL_FIND_ACCOUNT_ICON, COL_FIND_ACCOUNT_NAME, COL_FIND_ACCOUNT, COL_FIND_CHAT_NAME, COL_FIND_CHAT_ID, COL_FIND_IS_CHATROOM, COL_FIND_DATE, COL_FIND_DATE_READABLE, COL_FIND_COUNT }; enum { COL_CHAT_ICON, COL_CHAT_NAME, COL_CHAT_ACCOUNT, COL_CHAT_ID, COL_CHAT_IS_CHATROOM, COL_CHAT_COUNT }; static EmpathyLogWindow *log_window = NULL; static void account_manager_prepared_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object); EmpathyLogWindow *window = user_data; guint account_num; GList *accounts; GError *error = NULL; if (log_window == NULL) return; if (!tp_account_manager_prepare_finish (account_manager, result, &error)) { DEBUG ("Failed to prepare account manager: %s", error->message); g_error_free (error); return; } accounts = tp_account_manager_get_valid_accounts (account_manager); account_num = g_list_length (accounts); g_list_free (accounts); if (account_num > 1) { gtk_widget_show (window->vbox_chats); gtk_widget_show (window->account_chooser_chats); } else { gtk_widget_hide (window->vbox_chats); gtk_widget_hide (window->account_chooser_chats); } } static void account_chooser_ready_cb (EmpathyAccountChooser *chooser, EmpathyLogWindow *window) { gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1); log_window_chats_set_selected (window); } static void select_account_once_ready (EmpathyLogWindow *self, TpAccount *account, const gchar *chat_id, gboolean is_chatroom) { EmpathyAccountChooser *account_chooser = EMPATHY_ACCOUNT_CHOOSER (self->account_chooser_chats); self->selected_account = g_object_ref (account); self->selected_chat_id = g_strdup (chat_id); self->selected_is_chatroom = is_chatroom; if (empathy_account_chooser_is_ready (account_chooser)) account_chooser_ready_cb (account_chooser, self); else /* Chat will be selected once the account chooser is ready */ g_signal_connect (account_chooser, "ready", G_CALLBACK (account_chooser_ready_cb), self); } GtkWidget * empathy_log_window_show (TpAccount *account, const gchar *chat_id, gboolean is_chatroom, GtkWindow *parent) { EmpathyAccountChooser *account_chooser; TpAccountManager *account_manager; GtkBuilder *gui; gchar *filename; EmpathyLogWindow *window; if (log_window) { gtk_window_present (GTK_WINDOW (log_window->window)); if (account && chat_id) { gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook), 1); select_account_once_ready (log_window, account, chat_id, is_chatroom); } return log_window->window; } log_window = g_new0 (EmpathyLogWindow, 1); log_window->log_manager = tpl_log_manager_dup_singleton (); window = log_window; filename = empathy_file_lookup ("empathy-log-window.ui", "libempathy-gtk"); gui = empathy_builder_get_file (filename, "log_window", &window->window, "notebook", &window->notebook, "entry_find", &window->entry_find, "button_find", &window->button_find, "treeview_find", &window->treeview_find, "scrolledwindow_find", &window->scrolledwindow_find, "button_previous", &window->button_previous, "button_next", &window->button_next, "entry_chats", &window->entry_chats, "calendar_chats", &window->calendar_chats, "vbox_chats", &window->vbox_chats, "treeview_chats", &window->treeview_chats, "scrolledwindow_chats", &window->scrolledwindow_chats, NULL); g_free (filename); empathy_builder_connect (gui, window, "log_window", "destroy", log_window_destroy_cb, "entry_find", "changed", log_window_entry_find_changed_cb, "entry_find", "activate", log_window_entry_find_activate_cb, "button_previous", "clicked", log_window_button_previous_clicked_cb, "button_next", "clicked", log_window_button_next_clicked_cb, "button_find", "clicked", log_window_button_find_clicked_cb, "entry_chats", "changed", log_window_entry_chats_changed_cb, "entry_chats", "activate", log_window_entry_chats_activate_cb, NULL); g_object_unref (gui); g_object_add_weak_pointer (G_OBJECT (window->window), (gpointer) &log_window); /* We set this up here so we can block it when needed. */ g_signal_connect (window->calendar_chats, "day-selected", G_CALLBACK (log_window_calendar_chats_day_selected_cb), window); g_signal_connect (window->calendar_chats, "month-changed", G_CALLBACK (log_window_calendar_chats_month_changed_cb), window); /* Configure Search EmpathyChatView */ window->chatview_find = empathy_theme_manager_create_view (empathy_theme_manager_get ()); gtk_container_add (GTK_CONTAINER (window->scrolledwindow_find), GTK_WIDGET (window->chatview_find)); gtk_widget_show (GTK_WIDGET (window->chatview_find)); /* Configure Contacts EmpathyChatView */ window->chatview_chats = empathy_theme_manager_create_view (empathy_theme_manager_get ()); gtk_container_add (GTK_CONTAINER (window->scrolledwindow_chats), GTK_WIDGET (window->chatview_chats)); gtk_widget_show (GTK_WIDGET (window->chatview_chats)); /* Account chooser for chats */ window->account_chooser_chats = empathy_account_chooser_new (); account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); gtk_box_pack_start (GTK_BOX (window->vbox_chats), window->account_chooser_chats, FALSE, TRUE, 0); g_signal_connect (window->account_chooser_chats, "changed", G_CALLBACK (log_window_chats_accounts_changed_cb), window); /* Populate */ account_manager = tp_account_manager_dup (); tp_account_manager_prepare_async (account_manager, NULL, account_manager_prepared_cb, window); g_object_unref (account_manager); /* Search List */ log_window_find_setup (window); /* Contacts */ log_window_chats_setup (window); log_window_chats_populate (window); if (account && chat_id) select_account_once_ready (window, account, chat_id, is_chatroom); if (parent) { gtk_window_set_transient_for (GTK_WINDOW (window->window), GTK_WINDOW (parent)); } gtk_widget_show (window->window); return window->window; } static void log_window_destroy_cb (GtkWidget *widget, EmpathyLogWindow *window) { g_free (window->last_find); g_object_unref (window->log_manager); tp_clear_object (&window->selected_account); g_free (window->selected_chat_id); g_free (window); } /* * Search code. */ static void log_window_entry_find_changed_cb (GtkWidget *entry, EmpathyLogWindow *window) { const gchar *str; gboolean is_sensitive = TRUE; str = gtk_entry_get_text (GTK_ENTRY (window->entry_find)); is_sensitive &= !EMP_STR_EMPTY (str); is_sensitive &= !window->last_find || (window->last_find && strcmp (window->last_find, str) != 0); gtk_widget_set_sensitive (window->button_find, is_sensitive); } static void got_messages_for_date_cb (GObject *manager, GAsyncResult *result, gpointer user_data) { EmpathyLogWindow *window = user_data; GList *messages; GList *l; gboolean can_do_previous; gboolean can_do_next; GError *error = NULL; if (log_window == NULL) return; if (!tpl_log_manager_get_messages_for_date_finish (TPL_LOG_MANAGER (manager), result, &messages, &error)) { DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting", error->message); empathy_chat_view_append_event (window->chatview_find, "Unable to retrieve messages for the selected date"); g_error_free (error); return; } for (l = messages; l; l = l->next) { EmpathyMessage *message; g_assert (TPL_IS_ENTRY (l->data)); message = empathy_message_from_tpl_log_entry (l->data); g_object_unref (l->data); empathy_chat_view_append_message (window->chatview_find, message); g_object_unref (message); } g_list_free (messages); /* Scroll to the most recent messages */ empathy_chat_view_scroll (window->chatview_find, TRUE); /* Highlight and find messages */ empathy_chat_view_highlight (window->chatview_find, window->last_find, FALSE); empathy_chat_view_find_next (window->chatview_find, window->last_find, TRUE, FALSE); empathy_chat_view_find_abilities (window->chatview_find, window->last_find, FALSE, &can_do_previous, &can_do_next); gtk_widget_set_sensitive (window->button_previous, can_do_previous); gtk_widget_set_sensitive (window->button_next, can_do_next); gtk_widget_set_sensitive (window->button_find, FALSE); } static GDate * gdate_from_str (const gchar *str) { guint u; guint day, month, year; if (sscanf (str, "%u", &u) != 1) return NULL; day = (u % 100); month = ((u / 100) % 100); year = (u / 10000); if (!g_date_valid_dmy (day, month, year)) return NULL; return g_date_new_dmy (day, month, year); } static void log_window_find_changed_cb (GtkTreeSelection *selection, EmpathyLogWindow *window) { GtkTreeView *view; GtkTreeModel *model; GtkTreeIter iter; TpAccount *account; gchar *chat_id; gboolean is_chatroom; gchar *date; GDate *gdate; /* Get selected information */ view = GTK_TREE_VIEW (window->treeview_find); model = gtk_tree_view_get_model (view); if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { gtk_widget_set_sensitive (window->button_previous, FALSE); gtk_widget_set_sensitive (window->button_next, FALSE); empathy_chat_view_clear (window->chatview_find); return; } gtk_widget_set_sensitive (window->button_previous, TRUE); gtk_widget_set_sensitive (window->button_next, TRUE); gtk_tree_model_get (model, &iter, COL_FIND_ACCOUNT, &account, COL_FIND_CHAT_ID, &chat_id, COL_FIND_IS_CHATROOM, &is_chatroom, COL_FIND_DATE, &date, -1); /* Clear all current messages shown in the textview */ empathy_chat_view_clear (window->chatview_find); /* Turn off scrolling temporarily */ empathy_chat_view_scroll (window->chatview_find, FALSE); /* Get messages */ gdate = gdate_from_str (date); if (gdate != NULL) { tpl_log_manager_get_messages_for_date_async (window->log_manager, account, chat_id, is_chatroom, gdate, got_messages_for_date_cb, window); g_date_free (gdate); } g_object_unref (account); g_free (date); g_free (chat_id); } static void log_manager_searched_new_cb (GObject *manager, GAsyncResult *result, gpointer user_data) { GList *hits; GList *l; GtkTreeIter iter; GtkListStore *store = user_data; GError *error = NULL; if (log_window == NULL) return; if (!tpl_log_manager_search_finish (TPL_LOG_MANAGER (manager), result, &hits, &error)) { DEBUG ("%s. Aborting", error->message); g_error_free (error); return; } for (l = hits; l; l = l->next) { TplLogSearchHit *hit; const gchar *account_name; const gchar *account_icon; gchar date_readable[255]; gchar tmp[255]; hit = l->data; /* Protect against invalid data (corrupt or old log files. */ if (!hit->account || !hit->chat_id) { continue; } g_date_strftime (date_readable, sizeof (date_readable), EMPATHY_DATE_FORMAT_DISPLAY_SHORT, hit->date); g_date_strftime (tmp, sizeof (tmp), "%Y%m%d", hit->date); account_name = tp_account_get_display_name (hit->account); account_icon = tp_account_get_icon_name (hit->account); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, COL_FIND_ACCOUNT_ICON, account_icon, COL_FIND_ACCOUNT_NAME, account_name, COL_FIND_ACCOUNT, hit->account, COL_FIND_CHAT_NAME, hit->chat_id, /* FIXME */ COL_FIND_CHAT_ID, hit->chat_id, COL_FIND_IS_CHATROOM, hit->is_chatroom, COL_FIND_DATE, tmp, COL_FIND_DATE_READABLE, date_readable, -1); /* FIXME: Update COL_FIND_CHAT_NAME */ if (hit->is_chatroom) { } else { } } if (hits) { tpl_log_manager_search_free (hits); } } static void log_window_find_populate (EmpathyLogWindow *window, const gchar *search_criteria) { GtkTreeView *view; GtkTreeModel *model; GtkTreeSelection *selection; GtkListStore *store; view = GTK_TREE_VIEW (window->treeview_find); model = gtk_tree_view_get_model (view); selection = gtk_tree_view_get_selection (view); store = GTK_LIST_STORE (model); empathy_chat_view_clear (window->chatview_find); gtk_list_store_clear (store); if (EMP_STR_EMPTY (search_criteria)) { /* Just clear the search. */ return; } tpl_log_manager_search_async (window->log_manager, search_criteria, log_manager_searched_new_cb, (gpointer) store); } static void log_window_find_setup (EmpathyLogWindow *window) { GtkTreeView *view; GtkTreeModel *model; GtkTreeSelection *selection; GtkTreeSortable *sortable; GtkTreeViewColumn *column; GtkListStore *store; GtkCellRenderer *cell; gint offset; view = GTK_TREE_VIEW (window->treeview_find); selection = gtk_tree_view_get_selection (view); /* New store */ store = gtk_list_store_new (COL_FIND_COUNT, G_TYPE_STRING, /* account icon name */ G_TYPE_STRING, /* account name */ TP_TYPE_ACCOUNT, /* account */ G_TYPE_STRING, /* chat name */ G_TYPE_STRING, /* chat id */ G_TYPE_BOOLEAN, /* is chatroom */ G_TYPE_STRING, /* date */ G_TYPE_STRING); /* date_readable */ model = GTK_TREE_MODEL (store); sortable = GTK_TREE_SORTABLE (store); gtk_tree_view_set_model (view, model); /* New column */ column = gtk_tree_view_column_new (); cell = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, cell, FALSE); gtk_tree_view_column_add_attribute (column, cell, "icon-name", COL_FIND_ACCOUNT_ICON); cell = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, cell, TRUE); gtk_tree_view_column_add_attribute (column, cell, "text", COL_FIND_ACCOUNT_NAME); gtk_tree_view_column_set_title (column, _("Account")); gtk_tree_view_append_column (view, column); gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_column_set_clickable (column, TRUE); cell = gtk_cell_renderer_text_new (); offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Conversation"), cell, "text", COL_FIND_CHAT_NAME, NULL); column = gtk_tree_view_get_column (view, offset - 1); gtk_tree_view_column_set_sort_column_id (column, COL_FIND_CHAT_NAME); gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_column_set_clickable (column, TRUE); cell = gtk_cell_renderer_text_new (); offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Date"), cell, "text", COL_FIND_DATE_READABLE, NULL); column = gtk_tree_view_get_column (view, offset - 1); gtk_tree_view_column_set_sort_column_id (column, COL_FIND_DATE); gtk_tree_view_column_set_resizable (column, TRUE); gtk_tree_view_column_set_clickable (column, TRUE); /* Set up treeview properties */ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); gtk_tree_sortable_set_sort_column_id (sortable, COL_FIND_DATE, GTK_SORT_ASCENDING); /* Set up signals */ g_signal_connect (selection, "changed", G_CALLBACK (log_window_find_changed_cb), window); g_object_unref (store); } static void start_find_search (EmpathyLogWindow *window) { const gchar *str; str = gtk_entry_get_text (GTK_ENTRY (window->entry_find)); /* Don't find the same crap again */ if (window->last_find && strcmp (window->last_find, str) == 0) { return; } g_free (window->last_find); window->last_find = g_strdup (str); log_window_find_populate (window, str); } static void log_window_button_find_clicked_cb (GtkWidget *widget, EmpathyLogWindow *window) { start_find_search (window); } static void log_window_entry_find_activate_cb (GtkWidget *entry, EmpathyLogWindow *self) { start_find_search (self); } static void log_window_button_next_clicked_cb (GtkWidget *widget, EmpathyLogWindow *window) { if (window->last_find) { gboolean can_do_previous; gboolean can_do_next; empathy_chat_view_find_next (window->chatview_find, window->last_find, FALSE, FALSE); empathy_chat_view_find_abilities (window->chatview_find, window->last_find, FALSE, &can_do_previous, &can_do_next); gtk_widget_set_sensitive (window->button_previous, can_do_previous); gtk_widget_set_sensitive (window->button_next, can_do_next); } } static void log_window_button_previous_clicked_cb (GtkWidget *widget, EmpathyLogWindow *window) { if (window->last_find) { gboolean can_do_previous; gboolean can_do_next; empathy_chat_view_find_previous (window->chatview_find, window->last_find, FALSE, FALSE); empathy_chat_view_find_abilities (window->chatview_find, window->last_find, FALSE, &can_do_previous, &can_do_next); gtk_widget_set_sensitive (window->button_previous, can_do_previous); gtk_widget_set_sensitive (window->button_next, can_do_next); } } /* * Chats Code */ static void log_window_chats_changed_cb (GtkTreeSelection *selection, EmpathyLogWindow *window) { /* Use last date by default */ gtk_calendar_clear_marks (GTK_CALENDAR (window->calendar_chats)); log_window_chats_get_messages (window, NULL); } static void log_manager_got_chats_cb (GObject *manager, GAsyncResult *result, gpointer user_data) { EmpathyLogWindow *window = user_data; GList *chats; GList *l; GtkTreeView *view; GtkTreeModel *model; GtkTreeSelection *selection; GtkListStore *store; GtkTreeIter iter; GError *error = NULL; if (log_window == NULL) return; if (!tpl_log_manager_get_chats_finish (TPL_LOG_MANAGER (manager), result, &chats, &error)) { DEBUG ("%s. Aborting", error->message); g_error_free (error); return; } view = GTK_TREE_VIEW (window->treeview_chats); model = gtk_tree_view_get_model (view); selection = gtk_tree_view_get_selection (view); store = GTK_LIST_STORE (model); for (l = chats; l; l = l->next) { TplLogSearchHit *hit; hit = l->data; if (hit->account == NULL) continue; gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, COL_CHAT_ICON, "empathy-available", /* FIXME */ COL_CHAT_NAME, hit->chat_id, COL_CHAT_ACCOUNT, hit->account, COL_CHAT_ID, hit->chat_id, COL_CHAT_IS_CHATROOM, hit->is_chatroom, -1); /* FIXME: Update COL_CHAT_ICON/NAME */ if (hit->is_chatroom) { } else { } } tpl_log_manager_search_free (chats); /* Unblock signals */ g_signal_handlers_unblock_by_func (selection, log_window_chats_changed_cb, window); } static void log_window_chats_populate (EmpathyLogWindow *window) { EmpathyAccountChooser *account_chooser; TpAccount *account; GtkTreeView *view; GtkTreeModel *model; GtkTreeSelection *selection; GtkListStore *store; account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); account = empathy_account_chooser_dup_account (account_chooser); view = GTK_TREE_VIEW (window->treeview_chats); model = gtk_tree_view_get_model (view); selection = gtk_tree_view_get_selection (view); store = GTK_LIST_STORE (model); if (account == NULL) { gtk_list_store_clear (store); return; } /* Block signals to stop the logs being retrieved prematurely */ g_signal_handlers_block_by_func (selection, log_window_chats_changed_cb, window); gtk_list_store_clear (store); tpl_log_manager_get_chats_async (window->log_manager, account, log_manager_got_chats_cb, (gpointer) window); } static void log_window_chats_setup (EmpathyLogWindow *window) { GtkTreeView *view; GtkTreeModel *model; GtkTreeSelection *selection; GtkTreeSortable *sortable; GtkTreeViewColumn *column; GtkListStore *store; GtkCellRenderer *cell; view = GTK_TREE_VIEW (window->treeview_chats); selection = gtk_tree_view_get_selection (view); /* new store */ store = gtk_list_store_new (COL_CHAT_COUNT, G_TYPE_STRING, /* icon */ G_TYPE_STRING, /* name */ TP_TYPE_ACCOUNT, /* account */ G_TYPE_STRING, /* id */ G_TYPE_BOOLEAN); /* is chatroom */ model = GTK_TREE_MODEL (store); sortable = GTK_TREE_SORTABLE (store); gtk_tree_view_set_model (view, model); /* new column */ column = gtk_tree_view_column_new (); cell = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, cell, FALSE); gtk_tree_view_column_add_attribute (column, cell, "icon-name", COL_CHAT_ICON); cell = gtk_cell_renderer_text_new (); g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL); gtk_tree_view_column_pack_start (column, cell, TRUE); gtk_tree_view_column_add_attribute (column, cell, "text", COL_CHAT_NAME); gtk_tree_view_append_column (view, column); /* set up treeview properties */ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); gtk_tree_sortable_set_sort_column_id (sortable, COL_CHAT_NAME, GTK_SORT_ASCENDING); /* set up signals */ g_signal_connect (selection, "changed", G_CALLBACK (log_window_chats_changed_cb), window); g_object_unref (store); } static void log_window_chats_accounts_changed_cb (GtkWidget *combobox, EmpathyLogWindow *window) { /* Clear all current messages shown in the textview */ empathy_chat_view_clear (window->chatview_chats); log_window_chats_populate (window); } static void log_window_chats_set_selected (EmpathyLogWindow *window) { EmpathyAccountChooser *account_chooser; GtkTreeView *view; GtkTreeModel *model; GtkTreeSelection *selection; GtkTreeIter iter; GtkTreePath *path; gboolean ok; account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats); empathy_account_chooser_set_account (account_chooser, window->selected_account); view = GTK_TREE_VIEW (window->treeview_chats); model = gtk_tree_view_get_model (view); selection = gtk_tree_view_get_selection (view); if (!gtk_tree_model_get_iter_first (model, &iter)) { return; } for (ok = TRUE; ok; ok = gtk_tree_model_iter_next (model, &iter)) { TpAccount *this_account; gchar *this_chat_id; gboolean this_is_chatroom; gtk_tree_model_get (model, &iter, COL_CHAT_ACCOUNT, &this_account, COL_CHAT_ID, &this_chat_id, COL_CHAT_IS_CHATROOM, &this_is_chatroom, -1); if (this_account == window->selected_account && strcmp (this_chat_id, window->selected_chat_id) == 0 && this_is_chatroom == window->selected_is_chatroom) { gtk_tree_selection_select_iter (selection, &iter); path = gtk_tree_model_get_path (model, &iter); gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0); gtk_tree_path_free (path); g_object_unref (this_account); g_free (this_chat_id); break; } g_object_unref (this_account); g_free (this_chat_id); } } static gboolean log_window_chats_get_selected (EmpathyLogWindow *window, TpAccount **account, gchar **chat_id, gboolean *is_chatroom) { GtkTreeView *view; GtkTreeModel *model; GtkTreeSelection *selection; GtkTreeIter iter; gchar *id = NULL; TpAccount *acc = NULL; gboolean room = FALSE; view = GTK_TREE_VIEW (window->treeview_chats); model = gtk_tree_view_get_model (view); selection = gtk_tree_view_get_selection (view); if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) { return FALSE; } gtk_tree_model_get (model, &iter, COL_CHAT_ACCOUNT, &acc, COL_CHAT_ID, &id, COL_CHAT_IS_CHATROOM, &room, -1); if (chat_id) { *chat_id = id; } else { g_free (id); } if (account) { *account = acc; } else { g_object_unref (acc); } if (is_chatroom) { *is_chatroom = room; } return TRUE; } static void log_window_got_messages_for_date_cb (GObject *manager, GAsyncResult *result, gpointer user_data) { EmpathyLogWindow *window = user_data; GList *messages; GList *l; GError *error = NULL; if (log_window == NULL) return; if (!tpl_log_manager_get_messages_for_date_finish (TPL_LOG_MANAGER (manager), result, &messages, &error)) { DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting", error->message); empathy_chat_view_append_event (window->chatview_find, "Unable to retrieve messages for the selected date"); g_error_free (error); return; } for (l = messages; l; l = l->next) { EmpathyMessage *message = empathy_message_from_tpl_log_entry (l->data); g_object_unref (l->data); empathy_chat_view_append_message (window->chatview_chats, message); g_object_unref (message); } g_list_free (messages); /* Turn back on scrolling */ empathy_chat_view_scroll (window->chatview_find, TRUE); /* Give the search entry main focus */ gtk_widget_grab_focus (window->entry_chats); } static void log_window_get_messages_for_date (EmpathyLogWindow *window, GDate *date) { TpAccount *account; gchar *chat_id; gboolean is_chatroom; if (!log_window_chats_get_selected (window, &account, &chat_id, &is_chatroom)) { return; } /* Clear all current messages shown in the textview */ empathy_chat_view_clear (window->chatview_chats); /* Turn off scrolling temporarily */ empathy_chat_view_scroll (window->chatview_find, FALSE); /* Get messages */ tpl_log_manager_get_messages_for_date_async (window->log_manager, account, chat_id, is_chatroom, date, log_window_got_messages_for_date_cb, (gpointer) window); } static void log_manager_got_dates_cb (GObject *manager, GAsyncResult *result, gpointer user_data) { EmpathyLogWindow *window = user_data; GList *dates; GList *l; guint year_selected; guint month_selected; gboolean day_selected = FALSE; GDate *date = NULL; GError *error = NULL; if (log_window == NULL) return; if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager), result, &dates, &error)) { DEBUG ("Unable to retrieve messages' dates: %s. Aborting", error->message); empathy_chat_view_append_event (window->chatview_find, "Unable to retrieve messages' dates"); return; } for (l = dates; l; l = l->next) { GDate *d = l->data; gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats), &year_selected, &month_selected, NULL); month_selected++; if (!l->next) { date = d; } if (g_date_get_year (d) != year_selected || g_date_get_month (d) != month_selected) { continue; } DEBUG ("Marking date: %04u-%02u-%02u", g_date_get_year (d), g_date_get_month (d), g_date_get_day (d)); gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), g_date_get_day (d)); if (l->next) { continue; } day_selected = TRUE; gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), g_date_get_day (d)); } if (!day_selected) { /* Unselect the day in the calendar */ gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), 0); } g_signal_handlers_unblock_by_func (window->calendar_chats, log_window_calendar_chats_day_selected_cb, window); if (date) { /* Show messages of the most recent date */ log_window_get_messages_for_date (window, date); } g_list_foreach (dates, (GFunc) g_free, NULL); g_list_free (dates); } static void log_window_chats_get_messages (EmpathyLogWindow *window, GDate *date) { TpAccount *account; gchar *chat_id; gboolean is_chatroom; guint year_selected; guint month_selected; guint day; if (!log_window_chats_get_selected (window, &account, &chat_id, &is_chatroom)) { return; } g_signal_handlers_block_by_func (window->calendar_chats, log_window_calendar_chats_day_selected_cb, window); /* Either use the supplied date or get the last */ if (date == NULL) { /* Get a list of dates and show them on the calendar */ tpl_log_manager_get_dates_async (window->log_manager, account, chat_id, is_chatroom, log_manager_got_dates_cb, (gpointer) window); /* signal unblocked at the end of the CB flow */ } else { day = g_date_get_day (date); gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats), &year_selected, &month_selected, NULL); month_selected++; if (g_date_get_year (date) != year_selected && g_date_get_month (date) != month_selected) { day = 0; } gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day); g_signal_handlers_unblock_by_func (window->calendar_chats, log_window_calendar_chats_day_selected_cb, window); } if (date != NULL) { /* Show messages of the selected date */ log_window_get_messages_for_date (window, date); } g_object_unref (account); g_free (chat_id); } static void log_window_calendar_chats_day_selected_cb (GtkWidget *calendar, EmpathyLogWindow *window) { guint year; guint month; guint day; GDate *date; gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day); if (day == 0) /* No date selected */ return; /* We need this hear because it appears that the months start from 0 */ month++; date = g_date_new_dmy (day, month, year); DEBUG ("Currently selected date is: %04u-%02u-%02u", year, month, day); log_window_chats_get_messages (window, date); g_date_free (date); } static void log_window_updating_calendar_month_cb (GObject *manager, GAsyncResult *result, gpointer user_data) { EmpathyLogWindow *window = user_data; GList *dates; GList *l; guint year_selected; guint month_selected; GError *error = NULL; if (log_window == NULL) return; if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager), result, &dates, &error)) { DEBUG ("Unable to retrieve messages' dates: %s. Aborting", error->message); empathy_chat_view_append_event (window->chatview_find, "Unable to retrieve messages' dates"); g_error_free (error); return; } gtk_calendar_clear_marks (GTK_CALENDAR (window->calendar_chats)); g_object_get (window->calendar_chats, "month", &month_selected, "year", &year_selected, NULL); /* We need this here because it appears that the months start from 0 */ month_selected++; for (l = dates; l; l = l->next) { GDate *date = l->data; if (g_date_get_year (date) == year_selected && g_date_get_month (date) == month_selected) { DEBUG ("Marking date: %04u-%02u-%02u", g_date_get_year (date), g_date_get_month (date), g_date_get_day (date)); gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), g_date_get_day (date)); } } g_list_foreach (dates, (GFunc) g_free, NULL); g_list_free (dates); DEBUG ("Currently showing month %d and year %d", month_selected, year_selected); } static void log_window_calendar_chats_month_changed_cb (GtkWidget *calendar, EmpathyLogWindow *window) { TpAccount *account; gchar *chat_id; gboolean is_chatroom; gtk_calendar_clear_marks (GTK_CALENDAR (calendar)); if (!log_window_chats_get_selected (window, &account, &chat_id, &is_chatroom)) { DEBUG ("No chat selected to get dates for..."); return; } /* Get the log object for this contact */ tpl_log_manager_get_dates_async (window->log_manager, account, chat_id, is_chatroom, log_window_updating_calendar_month_cb, (gpointer) window); g_object_unref (account); g_free (chat_id); } static void log_window_entry_chats_changed_cb (GtkWidget *entry, EmpathyLogWindow *window) { const gchar *str; str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats)); empathy_chat_view_highlight (window->chatview_chats, str, FALSE); if (str) { empathy_chat_view_find_next (window->chatview_chats, str, TRUE, FALSE); } } static void log_window_entry_chats_activate_cb (GtkWidget *entry, EmpathyLogWindow *window) { const gchar *str; str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats)); if (str) { empathy_chat_view_find_next (window->chatview_chats, str, FALSE, FALSE); } }