aboutsummaryrefslogtreecommitdiffstats
path: root/libempathy-gtk
diff options
context:
space:
mode:
Diffstat (limited to 'libempathy-gtk')
-rw-r--r--libempathy-gtk/Makefile.am2
-rw-r--r--libempathy-gtk/empathy-contact-widget.c5
-rw-r--r--libempathy-gtk/empathy-main-window.c3
-rw-r--r--libempathy-gtk/gossip-chat-view.c54
-rw-r--r--libempathy-gtk/gossip-chat.c25
-rw-r--r--libempathy-gtk/gossip-contact-list-store.c42
-rw-r--r--libempathy-gtk/gossip-log-window.c1153
-rw-r--r--libempathy-gtk/gossip-log-window.glade470
-rw-r--r--libempathy-gtk/gossip-log-window.h39
9 files changed, 1735 insertions, 58 deletions
diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am
index 6a6c7203c..113b37c3a 100644
--- a/libempathy-gtk/Makefile.am
+++ b/libempathy-gtk/Makefile.am
@@ -39,6 +39,7 @@ libempathy_gtk_la_SOURCES = \
gossip-account-chooser.c gossip-account-chooser.h \
gossip-new-chatroom-dialog.c gossip-new-chatroom-dialog.h \
gossip-chatrooms-window.c gossip-chatrooms-window.h \
+ gossip-log-window.c gossip-log-window.h \
gossip-ui-utils.c gossip-ui-utils.h
libempathy_gtk_la_LIBADD = \
@@ -61,6 +62,7 @@ glade_DATA = \
gossip-group-chat.glade \
gossip-chatrooms-window.glade \
gossip-spell-dialog.glade \
+ gossip-log-window.glade \
gossip-chat.glade
dtddir = $(datadir)/empathy
diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c
index e93117b36..ac43700d0 100644
--- a/libempathy-gtk/empathy-contact-widget.c
+++ b/libempathy-gtk/empathy-contact-widget.c
@@ -148,10 +148,7 @@ empathy_contact_widget_new (GossipContact *contact,
information = g_slice_new0 (EmpathyContactWidget);
information->editable = editable;
if (contact) {
- GossipContact *user_contact;
-
- user_contact = gossip_contact_get_user (contact);
- information->is_user = gossip_contact_equal (contact, user_contact);
+ information->is_user = gossip_contact_is_user (contact);
information->can_change_contact = FALSE;
} else {
information->is_user = FALSE;
diff --git a/libempathy-gtk/empathy-main-window.c b/libempathy-gtk/empathy-main-window.c
index 7f8693278..0e7b1fdda 100644
--- a/libempathy-gtk/empathy-main-window.c
+++ b/libempathy-gtk/empathy-main-window.c
@@ -50,6 +50,7 @@
#include "gossip-about-dialog.h"
#include "gossip-new-chatroom-dialog.h"
#include "gossip-chatrooms-window.h"
+#include "gossip-log-window.h"
#define DEBUG_DOMAIN "MainWindow"
@@ -533,7 +534,7 @@ static void
main_window_chat_history_cb (GtkWidget *widget,
EmpathyMainWindow *window)
{
- //gossip_log_window_show (NULL, NULL);
+ gossip_log_window_show (NULL, NULL, FALSE, GTK_WINDOW (window->window));
}
static void
diff --git a/libempathy-gtk/gossip-chat-view.c b/libempathy-gtk/gossip-chat-view.c
index 9fea2fbf1..e8db2628b 100644
--- a/libempathy-gtk/gossip-chat-view.c
+++ b/libempathy-gtk/gossip-chat-view.c
@@ -79,7 +79,7 @@ struct _GossipChatViewPriv {
BlockType last_block_type;
gboolean allow_scrolling;
- guint scroll_src;
+ guint scroll_timeout;
GTimer *scroll_time;
gboolean is_group_chat;
@@ -350,8 +350,8 @@ chat_view_finalize (GObject *object)
if (priv->scroll_time) {
g_timer_destroy (priv->scroll_time);
}
- if (priv->scroll_src) {
- g_source_remove (priv->scroll_src);
+ if (priv->scroll_timeout) {
+ g_source_remove (priv->scroll_timeout);
}
G_OBJECT_CLASS (gossip_chat_view_parent_class)->finalize (object);
@@ -382,7 +382,10 @@ chat_view_size_allocate (GtkWidget *widget,
GTK_WIDGET_CLASS (gossip_chat_view_parent_class)->size_allocate (widget, alloc);
if (down) {
- gossip_chat_view_scroll_down (GOSSIP_CHAT_VIEW (widget));
+ GtkAdjustment *adj;
+
+ adj = GTK_TEXT_VIEW (widget)->vadjustment;
+ gtk_adjustment_set_value (adj, adj->upper - adj->page_size);
}
}
@@ -1059,7 +1062,6 @@ chat_view_maybe_append_fancy_header (GossipChatView *view,
{
GossipChatViewPriv *priv;
GossipContact *sender;
- GossipContact *my_contact;
const gchar *name;
gboolean header;
GtkTextIter iter;
@@ -1075,9 +1077,8 @@ chat_view_maybe_append_fancy_header (GossipChatView *view,
priv = GET_PRIV (view);
sender = gossip_message_get_sender (msg);
- my_contact = gossip_contact_get_user (sender);
name = gossip_contact_get_name (sender);
- from_self = gossip_contact_equal (sender, my_contact);
+ from_self = gossip_contact_is_user (sender);
gossip_debug (DEBUG_DOMAIN, "Maybe add fancy header");
@@ -1186,7 +1187,6 @@ chat_view_append_irc_action (GossipChatView *view,
GossipMessage *msg)
{
GossipChatViewPriv *priv;
- GossipContact *my_contact;
GossipContact *sender;
const gchar *name;
GtkTextIter iter;
@@ -1199,11 +1199,9 @@ chat_view_append_irc_action (GossipChatView *view,
gossip_debug (DEBUG_DOMAIN, "Add IRC action");
sender = gossip_message_get_sender (msg);
- my_contact = gossip_contact_get_user (sender);
name = gossip_contact_get_name (sender);
- /* Skip the "/me ". */
- if (gossip_contact_equal (sender, my_contact)) {
+ if (gossip_contact_is_user (sender)) {
tag = "irc-action-self";
} else {
tag = "irc-action-other";
@@ -1236,7 +1234,6 @@ chat_view_append_fancy_action (GossipChatView *view,
{
GossipChatViewPriv *priv;
GossipContact *sender;
- GossipContact *my_contact;
const gchar *name;
const gchar *body;
GtkTextIter iter;
@@ -1249,10 +1246,9 @@ chat_view_append_fancy_action (GossipChatView *view,
gossip_debug (DEBUG_DOMAIN, "Add fancy action");
sender = gossip_message_get_sender (msg);
- my_contact = gossip_contact_get_user (sender);
name = gossip_contact_get_name (sender);
- if (gossip_contact_equal (sender, my_contact)) {
+ if (gossip_contact_is_user (sender)) {
tag = "fancy-action-self";
line_tag = "fancy-line-self";
} else {
@@ -1280,7 +1276,6 @@ chat_view_append_irc_message (GossipChatView *view,
{
GossipChatViewPriv *priv;
GossipContact *sender;
- GossipContact *my_contact;
const gchar *name;
const gchar *body;
const gchar *nick_tag;
@@ -1294,10 +1289,9 @@ chat_view_append_irc_message (GossipChatView *view,
body = gossip_message_get_body (msg);
sender = gossip_message_get_sender (msg);
- my_contact = gossip_contact_get_user (sender);
name = gossip_contact_get_name (sender);
- if (gossip_contact_equal (sender, my_contact)) {
+ if (gossip_contact_is_user (sender)) {
nick_tag = "irc-nick-self";
body_tag = "irc-body-self";
} else {
@@ -1338,16 +1332,14 @@ chat_view_append_fancy_message (GossipChatView *view,
{
GossipChatViewPriv *priv;
GossipContact *sender;
- GossipContact *my_contact;
const gchar *body;
const gchar *tag;
priv = GET_PRIV (view);
sender = gossip_message_get_sender (msg);
- my_contact = gossip_contact_get_user (sender);
- if (gossip_contact_equal (sender, my_contact)) {
+ if (gossip_contact_is_user (sender)) {
tag = "fancy-body-self";
} else {
tag = "fancy-body-other";
@@ -1441,7 +1433,6 @@ gossip_chat_view_append_message (GossipChatView *view,
{
GossipChatViewPriv *priv;
GossipContact *sender;
- GossipContact *my_contact;
const gchar *body;
gboolean scroll_down;
@@ -1480,14 +1471,12 @@ gossip_chat_view_append_message (GossipChatView *view,
}
}
- my_contact = gossip_contact_get_user (sender);
-
/* Reset the last inserted contact. */
if (priv->last_contact) {
g_object_unref (priv->last_contact);
}
- if (gossip_contact_equal (my_contact, sender)) {
+ if (gossip_contact_is_user (sender)) {
priv->last_block_type = BLOCK_TYPE_SELF;
priv->last_contact = NULL;
} else {
@@ -1658,7 +1647,7 @@ chat_view_scroll_cb (GossipChatView *view)
gtk_adjustment_set_value (adj, max_val);
g_timer_destroy (priv->scroll_time);
priv->scroll_time = NULL;
- priv->scroll_src = 0;
+ priv->scroll_timeout = 0;
return FALSE;
}
@@ -1683,16 +1672,15 @@ gossip_chat_view_scroll_down (GossipChatView *view)
gossip_debug (DEBUG_DOMAIN, "Scrolling down");
if (priv->scroll_time) {
- g_timer_destroy (priv->scroll_time);
+ g_timer_reset (priv->scroll_time);
+ } else {
+ priv->scroll_time = g_timer_new();
}
- if (priv->scroll_src) {
- g_source_remove (priv->scroll_src);
+ if (!priv->scroll_timeout) {
+ priv->scroll_timeout = g_timeout_add (SCROLL_DELAY,
+ (GSourceFunc) chat_view_scroll_cb,
+ view);
}
-
- priv->scroll_time = g_timer_new();
- priv->scroll_src = g_timeout_add (SCROLL_DELAY,
- (GSourceFunc) chat_view_scroll_cb,
- view);
}
gboolean
diff --git a/libempathy-gtk/gossip-chat.c b/libempathy-gtk/gossip-chat.c
index 0f6335617..657535d5a 100644
--- a/libempathy-gtk/gossip-chat.c
+++ b/libempathy-gtk/gossip-chat.c
@@ -341,9 +341,8 @@ static void
chat_send (GossipChat *chat,
const gchar *msg)
{
- GossipChatPriv *priv;
- GossipMessage *message;
- GossipContact *own_contact;
+ GossipChatPriv *priv;
+ GossipMessage *message;
priv = GET_PRIV (chat);
@@ -361,9 +360,7 @@ chat_send (GossipChat *chat,
/* FIXME: add here something to let group/privrate chat handle
* some special messages */
- own_contact = empathy_contact_manager_get_user (priv->manager, chat->account);
message = gossip_message_new (msg);
- gossip_message_set_sender (message, own_contact);
empathy_tp_chat_send (priv->tp_chat, message);
@@ -415,6 +412,7 @@ chat_message_received_cb (EmpathyTpChat *tp_chat,
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);
}
@@ -1035,14 +1033,12 @@ chat_state_changed_cb (EmpathyTpChat *tp_chat,
GossipChat *chat)
{
GossipChatPriv *priv;
- GossipContact *own_contact;
GList *l;
gboolean was_composing;
priv = GET_PRIV (chat);
- own_contact = gossip_contact_get_user (contact);
- if (gossip_contact_equal (own_contact, contact)) {
+ if (gossip_contact_is_user (contact)) {
/* We don't care about our own chat state */
return;
}
@@ -1112,7 +1108,8 @@ chat_add_logs (GossipChat *chat)
/* Add messages from last conversation */
messages = empathy_log_manager_get_last_messages (priv->log_manager,
chat->account,
- gossip_chat_get_id (chat));
+ 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++) {
@@ -1498,7 +1495,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;
@@ -1515,8 +1512,12 @@ gossip_chat_should_highlight_nick (GossipMessage *message)
return FALSE;
}
- my_contact = gossip_contact_get_user (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;
}
diff --git a/libempathy-gtk/gossip-contact-list-store.c b/libempathy-gtk/gossip-contact-list-store.c
index 4a5b5506e..887ce13e4 100644
--- a/libempathy-gtk/gossip-contact-list-store.c
+++ b/libempathy-gtk/gossip-contact-list-store.c
@@ -57,6 +57,7 @@ struct _GossipContactListStorePriv {
gboolean is_compact;
gboolean show_active;
GossipContactListStoreSort sort_criterium;
+ guint inhibit_active;
GossipContactGroupsFunc get_contact_groups;
gpointer get_contact_groups_data;
@@ -92,6 +93,7 @@ static void contact_list_store_set_property (GObject
const GValue *value,
GParamSpec *pspec);
static void contact_list_store_setup (GossipContactListStore *store);
+static gboolean contact_list_store_inibit_active_cb (GossipContactListStore *store);
static void contact_list_store_contact_added_cb (EmpathyContactList *list_iface,
GossipContact *contact,
GossipContactListStore *store);
@@ -231,9 +233,9 @@ gossip_contact_list_store_init (GossipContactListStore *store)
priv = GET_PRIV (store);
- priv->is_compact = FALSE;
- priv->show_active = TRUE;
- priv->show_avatars = TRUE;
+ priv->inhibit_active = g_timeout_add (1000,
+ (GSourceFunc) contact_list_store_inibit_active_cb,
+ store);
}
static void
@@ -249,6 +251,10 @@ contact_list_store_finalize (GObject *object)
g_object_unref (priv->list);
}
+ if (priv->inhibit_active) {
+ g_source_remove (priv->inhibit_active);
+ }
+
G_OBJECT_CLASS (gossip_contact_list_store_parent_class)->finalize (object);
}
@@ -320,7 +326,6 @@ gossip_contact_list_store_new (EmpathyContactList *list_iface)
GossipContactListStore *store;
GossipContactListStorePriv *priv;
GList *contacts, *l;
- gboolean show_active;
g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list_iface), NULL);
@@ -340,9 +345,7 @@ gossip_contact_list_store_new (EmpathyContactList *list_iface)
G_CALLBACK (contact_list_store_contact_removed_cb),
store);
- /* Add contacts already created. Do not highlight them. */
- show_active = priv->show_active;
- priv->show_active = FALSE;
+ /* Add contacts already created. */
contacts = empathy_contact_list_get_members (priv->list);
for (l = contacts; l; l = l->next) {
GossipContact *contact;
@@ -354,7 +357,6 @@ gossip_contact_list_store_new (EmpathyContactList *list_iface)
g_object_unref (contact);
}
g_list_free (contacts);
- priv->show_active = show_active;
return store;
}
@@ -681,6 +683,14 @@ void
gossip_contact_list_store_update_contact_groups (GossipContactListStore *store,
GossipContact *contact)
{
+ GossipContactListStorePriv *priv;
+ gboolean show_active;
+
+ g_return_if_fail (GOSSIP_IS_CONTACT_LIST_STORE (store));
+ g_return_if_fail (GOSSIP_IS_CONTACT (contact));
+
+ priv = GET_PRIV (store);
+
gossip_debug (DEBUG_DOMAIN, "Contact:'%s' updating groups",
gossip_contact_get_name (contact));
@@ -688,8 +698,11 @@ gossip_contact_list_store_update_contact_groups (GossipContactListStore *store,
* would have to check the groups already set up for each
* contact and then see what has been updated.
*/
+ show_active = priv->show_active;
+ priv->show_active = FALSE;
contact_list_store_remove_contact (store, contact);
contact_list_store_add_contact (store, contact);
+ priv->show_active = show_active;
}
static void
@@ -726,6 +739,19 @@ contact_list_store_setup (GossipContactListStore *store)
gossip_contact_list_store_set_sort_criterium (store, priv->sort_criterium);
}
+static gboolean
+contact_list_store_inibit_active_cb (GossipContactListStore *store)
+{
+ GossipContactListStorePriv *priv;
+
+ priv = GET_PRIV (store);
+
+ priv->show_active = TRUE;
+ priv->inhibit_active = 0;
+
+ return FALSE;
+}
+
static void
contact_list_store_contact_added_cb (EmpathyContactList *list_iface,
GossipContact *contact,
diff --git a/libempathy-gtk/gossip-log-window.c b/libempathy-gtk/gossip-log-window.c
new file mode 100644
index 000000000..3ec7cdb1d
--- /dev/null
+++ b/libempathy-gtk/gossip-log-window.c
@@ -0,0 +1,1153 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-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
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#include <libempathy/empathy-log-manager.h>
+#include <libempathy/gossip-chatroom-manager.h>
+#include <libempathy/gossip-chatroom.h>
+#include <libempathy/gossip-message.h>
+#include <libempathy/gossip-debug.h>
+#include <libempathy/gossip-utils.h>
+#include <libempathy/gossip-time.h>
+
+#include "gossip-log-window.h"
+#include "gossip-account-chooser.h"
+#include "gossip-chat-view.h"
+#include "gossip-ui-utils.h"
+
+#define DEBUG_DOMAIN "LogWindow"
+
+typedef struct {
+ GtkWidget *window;
+
+ GtkWidget *notebook;
+
+ GtkWidget *entry_find;
+ GtkWidget *button_find;
+ GtkWidget *treeview_find;
+ GtkWidget *scrolledwindow_find;
+ GossipChatView *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;
+ GossipChatView *chatview_chats;
+
+ gchar *last_find;
+
+ EmpathyLogManager *log_manager;
+} GossipLogWindow;
+
+static void
+log_window_destroy_cb (GtkWidget *widget,
+ GossipLogWindow *window);
+static void
+log_window_entry_find_changed_cb (GtkWidget *entry,
+ GossipLogWindow *window);
+static void
+log_window_find_changed_cb (GtkTreeSelection *selection,
+ GossipLogWindow *window);
+static void
+log_window_find_populate (GossipLogWindow *window,
+ const gchar *search_criteria);
+static void
+log_window_find_setup (GossipLogWindow *window);
+static void
+log_window_button_find_clicked_cb (GtkWidget *widget,
+ GossipLogWindow *window);
+static void
+log_window_button_next_clicked_cb (GtkWidget *widget,
+ GossipLogWindow *window);
+static void
+log_window_button_previous_clicked_cb (GtkWidget *widget,
+ GossipLogWindow *window);
+static void
+log_window_chats_changed_cb (GtkTreeSelection *selection,
+ GossipLogWindow *window);
+static void
+log_window_chats_populate (GossipLogWindow *window);
+static void
+log_window_chats_setup (GossipLogWindow *window);
+static void
+log_window_chats_accounts_changed_cb (GtkWidget *combobox,
+ GossipLogWindow *window);
+static void
+log_window_chats_new_message_cb (GossipContact *own_contact,
+ GossipMessage *message,
+ GossipLogWindow *window);
+//static gboolean
+//log_window_chats_is_today_selected (GossipLogWindow *window);
+static void
+log_window_chats_set_selected (GossipLogWindow *window,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean is_chatroom);
+static gboolean
+log_window_chats_get_selected (GossipLogWindow *window,
+ McAccount **account,
+ gchar **chat_id,
+ gboolean *is_chatroom);
+static void
+log_window_chats_get_messages (GossipLogWindow *window,
+ const gchar *date_to_show);
+static void
+log_window_calendar_chats_day_selected_cb (GtkWidget *calendar,
+ GossipLogWindow *window);
+static void
+log_window_calendar_chats_month_changed_cb (GtkWidget *calendar,
+ GossipLogWindow *window);
+static void
+log_window_entry_chats_changed_cb (GtkWidget *entry,
+ GossipLogWindow *window);
+static void
+log_window_entry_chats_activate_cb (GtkWidget *entry,
+ GossipLogWindow *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
+};
+
+void
+gossip_log_window_show (McAccount *account,
+ const gchar *chat_id,
+ gboolean is_chatroom,
+ GtkWindow *parent)
+{
+ static GossipLogWindow *window = NULL;
+ GossipAccountChooser *account_chooser;
+ GList *accounts;
+ gint account_num;
+ GladeXML *glade;
+
+ if (window) {
+ gtk_window_present (GTK_WINDOW (window->window));
+
+ if (account && chat_id) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1);
+ log_window_chats_set_selected (window, account,
+ chat_id, is_chatroom);
+ }
+
+ return;
+ }
+
+ window = g_new0 (GossipLogWindow, 1);
+ window->log_manager = empathy_log_manager_new ();
+
+ glade = gossip_glade_get_file ("gossip-log-window.glade",
+ "log_window",
+ NULL,
+ "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);
+ gossip_glade_connect (glade,
+ window,
+ "log_window", "destroy", log_window_destroy_cb,
+ "entry_find", "changed", log_window_entry_find_changed_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 (glade);
+
+ g_object_add_weak_pointer (G_OBJECT (window->window),
+ (gpointer) &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 GossipChatView */
+ window->chatview_find = gossip_chat_view_new ();
+ gtk_container_add (GTK_CONTAINER (window->scrolledwindow_find),
+ GTK_WIDGET (window->chatview_find));
+ gtk_widget_show (GTK_WIDGET (window->chatview_find));
+
+ /* Configure Contacts GossipChatView */
+ window->chatview_chats = gossip_chat_view_new ();
+ 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 = gossip_account_chooser_new ();
+ account_chooser = GOSSIP_ACCOUNT_CHOOSER (window->account_chooser_chats);
+ gossip_account_chooser_set_can_select_all (account_chooser, TRUE);
+
+ 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 */
+ accounts = mc_accounts_list ();
+ account_num = g_list_length (accounts);
+ mc_accounts_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);
+ }
+
+ /* Search List */
+ log_window_find_setup (window);
+
+ /* Contacts */
+ log_window_chats_setup (window);
+ log_window_chats_populate (window);
+
+ /* Select chat */
+ if (account && chat_id) {
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1);
+ log_window_chats_set_selected (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);
+}
+
+static void
+log_window_destroy_cb (GtkWidget *widget,
+ GossipLogWindow *window)
+{
+ g_signal_handlers_disconnect_by_func (window->log_manager,
+ log_window_chats_new_message_cb,
+ window);
+
+ g_free (window->last_find);
+ g_object_unref (window->log_manager);
+
+ g_free (window);
+}
+
+/*
+ * Search code.
+ */
+static void
+log_window_entry_find_changed_cb (GtkWidget *entry,
+ GossipLogWindow *window)
+{
+ const gchar *str;
+ gboolean is_sensitive = TRUE;
+
+ str = gtk_entry_get_text (GTK_ENTRY (window->entry_find));
+
+ is_sensitive &= !G_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
+log_window_find_changed_cb (GtkTreeSelection *selection,
+ GossipLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ McAccount *account;
+ gchar *chat_id;
+ gboolean is_chatroom;
+ gchar *date;
+ GossipMessage *message;
+ GList *messages;
+ GList *l;
+ gboolean can_do_previous;
+ gboolean can_do_next;
+
+ /* 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);
+
+ gossip_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 */
+ gossip_chat_view_clear (window->chatview_find);
+
+ /* Turn off scrolling temporarily */
+ gossip_chat_view_scroll (window->chatview_find, FALSE);
+
+ /* Get messages */
+ messages = empathy_log_manager_get_messages_for_date (window->log_manager,
+ account,
+ chat_id,
+ is_chatroom,
+ date);
+ g_object_unref (account);
+ g_free (date);
+ g_free (chat_id);
+
+ for (l = messages; l; l = l->next) {
+ message = l->data;
+ gossip_chat_view_append_message (window->chatview_find, message);
+ g_object_unref (message);
+ }
+ g_list_free (messages);
+
+ /* Scroll to the most recent messages */
+ gossip_chat_view_scroll (window->chatview_find, TRUE);
+
+ /* Highlight and find messages */
+ gossip_chat_view_highlight (window->chatview_find,
+ window->last_find);
+ gossip_chat_view_find_next (window->chatview_find,
+ window->last_find,
+ TRUE);
+ gossip_chat_view_find_abilities (window->chatview_find,
+ window->last_find,
+ &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 void
+log_window_find_populate (GossipLogWindow *window,
+ const gchar *search_criteria)
+{
+ GList *hits, *l;
+
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
+ GtkTreeIter iter;
+
+ 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);
+
+ gossip_chat_view_clear (window->chatview_find);
+
+ gtk_list_store_clear (store);
+
+ if (G_STR_EMPTY (search_criteria)) {
+ /* Just clear the search. */
+ return;
+ }
+
+ hits = empathy_log_manager_search_new (window->log_manager, search_criteria);
+
+ for (l = hits; l; l = l->next) {
+ EmpathyLogSearchHit *hit;
+ const gchar *account_name;
+ const gchar *account_icon;
+ gchar *date_readable;
+
+ hit = l->data;
+
+ /* Protect against invalid data (corrupt or old log files. */
+ if (!hit->account || !hit->chat_id) {
+ continue;
+ }
+
+ date_readable = empathy_log_manager_get_date_readable (hit->date);
+ account_name = mc_account_get_display_name (hit->account);
+ account_icon = gossip_icon_name_from_account (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, hit->date,
+ COL_FIND_DATE_READABLE, date_readable,
+ -1);
+
+ g_free (date_readable);
+
+ /* FIXME: Update COL_FIND_CHAT_NAME */
+ if (hit->is_chatroom) {
+ } else {
+ }
+ }
+
+ if (hits) {
+ empathy_log_manager_search_free (hits);
+ }
+}
+
+static void
+log_window_find_setup (GossipLogWindow *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 */
+ MC_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
+log_window_button_find_clicked_cb (GtkWidget *widget,
+ GossipLogWindow *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_next_clicked_cb (GtkWidget *widget,
+ GossipLogWindow *window)
+{
+ if (window->last_find) {
+ gboolean can_do_previous;
+ gboolean can_do_next;
+
+ gossip_chat_view_find_next (window->chatview_find,
+ window->last_find,
+ FALSE);
+ gossip_chat_view_find_abilities (window->chatview_find,
+ window->last_find,
+ &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,
+ GossipLogWindow *window)
+{
+ if (window->last_find) {
+ gboolean can_do_previous;
+ gboolean can_do_next;
+
+ gossip_chat_view_find_previous (window->chatview_find,
+ window->last_find,
+ FALSE);
+ gossip_chat_view_find_abilities (window->chatview_find,
+ window->last_find,
+ &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,
+ GossipLogWindow *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_window_chats_populate (GossipLogWindow *window)
+{
+ GossipAccountChooser *account_chooser;
+ McAccount *account;
+ GList *chats, *l;
+
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
+ GtkTreeIter iter;
+
+ account_chooser = GOSSIP_ACCOUNT_CHOOSER (window->account_chooser_chats);
+ account = gossip_account_chooser_get_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);
+
+ /* 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);
+
+ chats = empathy_log_manager_get_chats (window->log_manager, account);
+ for (l = chats; l; l = l->next) {
+ EmpathyLogSearchHit *hit;
+
+ hit = l->data;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_CHAT_ICON, "empathy-available",
+ COL_CHAT_NAME, hit->chat_id,
+ COL_CHAT_ACCOUNT, 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 {
+ }
+ }
+ empathy_log_manager_search_free (chats);
+
+ /* Unblock signals */
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_chats_changed_cb,
+ window);
+
+
+ g_object_unref (account);
+}
+
+static void
+log_window_chats_setup (GossipLogWindow *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 */
+ MC_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,
+ GossipLogWindow *window)
+{
+ /* Clear all current messages shown in the textview */
+ gossip_chat_view_clear (window->chatview_chats);
+
+ log_window_chats_populate (window);
+}
+
+static void
+log_window_chats_new_message_cb (GossipContact *own_contact,
+ GossipMessage *message,
+ GossipLogWindow *window)
+{
+ gossip_chat_view_append_message (window->chatview_chats, message);
+
+ /* Scroll to the most recent messages */
+ gossip_chat_view_scroll_down (window->chatview_chats);
+}
+
+#if 0
+static gboolean
+log_window_chats_is_today_selected (GossipLogWindow *window)
+{
+ GossipTime t;
+ gchar *timestamp;
+ guint year_selected;
+ guint year;
+ guint month;
+ guint month_selected;
+ guint day;
+ guint day_selected;
+ gboolean selected;
+
+ t = gossip_time_get_current ();
+ timestamp = gossip_time_to_string_local (t, "%Y%m%d");
+
+ sscanf (timestamp, "%4d%2d%2d", &year, &month, &day);
+
+ gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
+ &year_selected,
+ &month_selected,
+ &day_selected);
+
+ /* Hack since this starts at 0 */
+ month_selected++;
+
+ selected = (day_selected == day &&
+ month_selected == month &&
+ year_selected == year);
+
+ g_free (timestamp);
+
+ return selected;
+}
+#endif
+
+static void
+log_window_chats_set_selected (GossipLogWindow *window,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean is_chatroom)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gboolean ok;
+
+ 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)) {
+ McAccount *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 (gossip_account_equal (this_account, account) &&
+ strcmp (this_chat_id, chat_id) == 0 &&
+ this_is_chatroom == 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 (GossipLogWindow *window,
+ McAccount **account,
+ gchar **chat_id,
+ gboolean *is_chatroom)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ gchar *id = NULL;
+ McAccount *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_chats_get_messages (GossipLogWindow *window,
+ const gchar *date_to_show)
+{
+ McAccount *account;
+ gchar *chat_id;
+ gboolean is_chatroom;
+ GossipMessage *message;
+ GList *messages;
+ GList *dates = NULL;
+ GList *l;
+ const gchar *date;
+ guint year_selected;
+ guint year;
+ guint month;
+ 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 */
+ date = date_to_show;
+ if (!date) {
+ gboolean day_selected = FALSE;
+
+ /* Get a list of dates and show them on the calendar */
+ dates = empathy_log_manager_get_dates (window->log_manager,
+ account, chat_id,
+ is_chatroom);
+
+ for (l = dates; l; l = l->next) {
+ const gchar *str;
+
+ str = l->data;
+ if (!str) {
+ continue;
+ }
+
+ sscanf (str, "%4d%2d%2d", &year, &month, &day);
+ gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
+ &year_selected,
+ &month_selected,
+ NULL);
+
+ month_selected++;
+
+ if (!l->next) {
+ date = str;
+ }
+
+ if (year != year_selected || month != month_selected) {
+ continue;
+ }
+
+
+ gossip_debug (DEBUG_DOMAIN, "Marking date:'%s'", str);
+ gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day);
+
+ if (l->next) {
+ continue;
+ }
+
+ day_selected = TRUE;
+
+ gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day);
+ }
+
+ if (!day_selected) {
+ /* Unselect the day in the calendar */
+ gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), 0);
+ }
+ } else {
+ sscanf (date, "%4d%2d%2d", &year, &month, &day);
+ gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
+ &year_selected,
+ &month_selected,
+ NULL);
+
+ month_selected++;
+
+ if (year != year_selected && month != 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);
+
+ /* Clear all current messages shown in the textview */
+ gossip_chat_view_clear (window->chatview_chats);
+
+ /* Turn off scrolling temporarily */
+ gossip_chat_view_scroll (window->chatview_find, FALSE);
+
+ /* Get messages */
+ messages = empathy_log_manager_get_messages_for_date (window->log_manager,
+ account, chat_id,
+ is_chatroom,
+ date);
+
+ for (l = messages; l; l = l->next) {
+ message = l->data;
+
+ gossip_chat_view_append_message (window->chatview_chats,
+ message);
+ g_object_unref (message);
+ }
+ g_list_free (messages);
+
+ g_list_foreach (dates, (GFunc) g_free, NULL);
+ g_list_free (dates);
+
+ g_object_unref (account);
+ g_free (chat_id);
+
+ /* Turn back on scrolling */
+ gossip_chat_view_scroll (window->chatview_find, TRUE);
+
+ /* Scroll to the most recent messages */
+ gossip_chat_view_scroll_down (window->chatview_chats);
+
+ /* Give the search entry main focus */
+ gtk_widget_grab_focus (window->entry_chats);
+}
+
+static void
+log_window_calendar_chats_day_selected_cb (GtkWidget *calendar,
+ GossipLogWindow *window)
+{
+ guint year;
+ guint month;
+ guint day;
+
+ gchar *date;
+
+ gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day);
+
+ /* We need this hear because it appears that the months start from 0 */
+ month++;
+
+ date = g_strdup_printf ("%4.4d%2.2d%2.2d", year, month, day);
+
+ gossip_debug (DEBUG_DOMAIN, "Currently selected date is:'%s'", date);
+
+ log_window_chats_get_messages (window, date);
+
+ g_free (date);
+}
+
+static void
+log_window_calendar_chats_month_changed_cb (GtkWidget *calendar,
+ GossipLogWindow *window)
+{
+ McAccount *account;
+ gchar *chat_id;
+ gboolean is_chatroom;
+ guint year_selected;
+ guint month_selected;
+
+ GList *dates;
+ GList *l;
+
+ gtk_calendar_clear_marks (GTK_CALENDAR (calendar));
+
+ if (!log_window_chats_get_selected (window, &account,
+ &chat_id, &is_chatroom)) {
+ gossip_debug (DEBUG_DOMAIN, "No chat selected to get dates for...");
+ return;
+ }
+
+ g_object_get (calendar,
+ "month", &month_selected,
+ "year", &year_selected,
+ NULL);
+
+ /* We need this hear because it appears that the months start from 0 */
+ month_selected++;
+
+ /* Get the log object for this contact */
+ dates = empathy_log_manager_get_dates (window->log_manager, account,
+ chat_id, is_chatroom);
+ g_object_unref (account);
+ g_free (chat_id);
+
+ for (l = dates; l; l = l->next) {
+ const gchar *str;
+ guint year;
+ guint month;
+ guint day;
+
+ str = l->data;
+ if (!str) {
+ continue;
+ }
+
+ sscanf (str, "%4d%2d%2d", &year, &month, &day);
+
+ if (year == year_selected && month == month_selected) {
+ gossip_debug (DEBUG_DOMAIN, "Marking date:'%s'", str);
+ gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day);
+ }
+ }
+
+ g_list_foreach (dates, (GFunc) g_free, NULL);
+ g_list_free (dates);
+
+ gossip_debug (DEBUG_DOMAIN,
+ "Currently showing month %d and year %d",
+ month_selected, year_selected);
+}
+
+static void
+log_window_entry_chats_changed_cb (GtkWidget *entry,
+ GossipLogWindow *window)
+{
+ const gchar *str;
+
+ str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
+ gossip_chat_view_highlight (window->chatview_chats, str);
+
+ if (str) {
+ gossip_chat_view_find_next (window->chatview_chats,
+ str,
+ TRUE);
+ }
+}
+
+static void
+log_window_entry_chats_activate_cb (GtkWidget *entry,
+ GossipLogWindow *window)
+{
+ const gchar *str;
+
+ str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
+
+ if (str) {
+ gossip_chat_view_find_next (window->chatview_chats,
+ str,
+ FALSE);
+ }
+}
+
diff --git a/libempathy-gtk/gossip-log-window.glade b/libempathy-gtk/gossip-log-window.glade
new file mode 100644
index 000000000..4309a3544
--- /dev/null
+++ b/libempathy-gtk/gossip-log-window.glade
@@ -0,0 +1,470 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="log_window">
+ <property name="title" translatable="yes">View Previous Conversations</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">640</property>
+ <property name="default_height">450</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="icon_name">gtk-justify-left</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox192">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox144">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label628">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_For:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">entry_find</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_find">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_find">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-find</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="position">120</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow14">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview_find">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox215">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow_find">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox171">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <placeholder/>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_next">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-media-next</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button_previous">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-media-previous</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="shrink">True</property>
+ <property name="resize">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label595">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Search</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table7">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox143">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkImage" id="image247">
+ <property name="visible">True</property>
+ <property name="stock">gtk-find</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="entry_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox191">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow13">
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="treeview_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCalendar" id="calendar_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="display_options">GTK_CALENDAR_SHOW_HEADING|GTK_CALENDAR_SHOW_DAY_NAMES</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow_chats">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox_chats">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label596">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Conversations</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/libempathy-gtk/gossip-log-window.h b/libempathy-gtk/gossip-log-window.h
new file mode 100644
index 000000000..7801072fd
--- /dev/null
+++ b/libempathy-gtk/gossip-log-window.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2006-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
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Martyn Russell <martyn@imendio.com>
+ * Xavier Claessens <xclaesse@gmail.com>
+ */
+
+#ifndef __GOSSIP_LOG_WINDOW_H__
+#define __GOSSIP_LOG_WINDOW_H__
+
+#include <libmissioncontrol/mc-account.h>
+
+G_BEGIN_DECLS
+
+void gossip_log_window_show (McAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom,
+ GtkWindow *parent);
+
+G_END_DECLS
+
+#endif /* __GOSSIP_LOG_WINDOW_H__ */