aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Claessens <xclaesse@gmail.com>2007-06-14 05:58:16 +0800
committerXavier Claessens <xclaesse@src.gnome.org>2007-06-14 05:58:16 +0800
commit4ce14ebec31f60a4a6bdd781f88607731912f557 (patch)
tree0ee31695ccdd06cae5f5b09bf5098707528b1dd3
parente24e8894479c1b69364faeb315ab0d0dbf7989f1 (diff)
downloadgsoc2013-empathy-4ce14ebec31f60a4a6bdd781f88607731912f557.tar
gsoc2013-empathy-4ce14ebec31f60a4a6bdd781f88607731912f557.tar.gz
gsoc2013-empathy-4ce14ebec31f60a4a6bdd781f88607731912f557.tar.bz2
gsoc2013-empathy-4ce14ebec31f60a4a6bdd781f88607731912f557.tar.lz
gsoc2013-empathy-4ce14ebec31f60a4a6bdd781f88607731912f557.tar.xz
gsoc2013-empathy-4ce14ebec31f60a4a6bdd781f88607731912f557.tar.zst
gsoc2013-empathy-4ce14ebec31f60a4a6bdd781f88607731912f557.zip
New window for viewing logs.
2007-06-13 Xavier Claessens <xclaesse@gmail.com> * libempathy-gtk/Makefile.am: * libempathy-gtk/gossip-log-window.glade: * libempathy-gtk/gossip-log-window.h: * libempathy-gtk/gossip-log-window.c: * libempathy/empathy-log-manager.c: * libempathy/empathy-log-manager.h: * libempathy-gtk/gossip-chat.c: * libempathy-gtk/empathy-main-window.c: New window for viewing logs. * libempathy-gtk/gossip-chat-view.c: Do not use smooth scroll when resizing the view. * libempathy-gtk/gossip-contact-list-store.c: Do not set active contacts when creating the store, and when contact groups changed. * src/empathy-main.c: Fix warning when using command-line options. * libempathy/empathy-tp-contact-list.c: Check if we have an aliasing iface before setting the alias of a contact. * TODO: Updated. * data/jabber.profile: Ignore ssl errors by default. This is a security vulnerability but we don't really have the choice. * libempathy/gossip-contact.h: * libempathy/gossip-contact.c: Add a "is-user" property to know if it's our self contact. * libempathy/gossip-message.h: * libempathy/gossip-message.c: Add a "receiver" property like that we have our self contact for nick highlight. svn path=/trunk/; revision=148
-rw-r--r--ChangeLog35
-rw-r--r--TODO8
-rw-r--r--data/jabber.profile1
-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
-rw-r--r--libempathy/empathy-log-manager.c376
-rw-r--r--libempathy/empathy-log-manager.h23
-rw-r--r--libempathy/empathy-tp-chat.c6
-rw-r--r--libempathy/empathy-tp-contact-list.c6
-rw-r--r--libempathy/gossip-contact.c79
-rw-r--r--libempathy/gossip-contact.h4
-rw-r--r--libempathy/gossip-message.c56
-rw-r--r--libempathy/gossip-message.h3
-rw-r--r--src/empathy-main.c1
21 files changed, 2243 insertions, 148 deletions
diff --git a/ChangeLog b/ChangeLog
index 22557f221..98ca5b05a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2007-06-13 Xavier Claessens <xclaesse@gmail.com>
+
+ * libempathy-gtk/Makefile.am:
+ * libempathy-gtk/gossip-log-window.glade:
+ * libempathy-gtk/gossip-log-window.h:
+ * libempathy-gtk/gossip-log-window.c:
+ * libempathy/empathy-log-manager.c:
+ * libempathy/empathy-log-manager.h:
+ * libempathy-gtk/gossip-chat.c:
+ * libempathy-gtk/empathy-main-window.c: New window for viewing logs.
+
+ * libempathy-gtk/gossip-chat-view.c: Do not use smooth scroll when
+ resizing the view.
+
+ * libempathy-gtk/gossip-contact-list-store.c: Do not set active
+ contacts when creating the store, and when contact groups changed.
+
+ * src/empathy-main.c: Fix warning when using command-line options.
+
+ * libempathy/empathy-tp-contact-list.c: Check if we have an aliasing
+ iface before setting the alias of a contact.
+
+ * TODO: Updated.
+
+ * data/jabber.profile: Ignore ssl errors by default. This is a security
+ vulnerability but we don't really have the choice.
+
+ * libempathy/gossip-contact.h:
+ * libempathy/gossip-contact.c: Add a "is-user" property to know if
+ it's our self contact.
+
+ * libempathy/gossip-message.h:
+ * libempathy/gossip-message.c: Add a "receiver" property like that we
+ have our self contact for nick highlight.
+
2007-06-10 Xavier Claessens <xclaesse@gmail.com>
* libempathy-gtk/gossip-spell-dialog.glade:
diff --git a/TODO b/TODO
index 5be759c2e..a11170104 100644
--- a/TODO
+++ b/TODO
@@ -2,14 +2,18 @@ Things you can do if you want to help:
- Rename all files and functions name to use the empathy namespace. Bug #444490.
- Porting gossip-account-widget-*.{c,h} from gossip project (Guillaume is already working on IRC widget).
- - Porting various UI widgets from gossip to libempathy-gtk for contact info, adding contact, personal info, etc.
- - GtkWidget-ify gossip widgets imported in libempathy-gtk. Actually most window/dialog do not inherit from GtkWindow/GtkDialog. Need to create a glade catalog.
+ - UI for inviting a contact in a chatroom.
+ - UI for accept/refuse invitation to join a chatroom.
+ - UI to send a message directly to a contact.
+ - GtkWidget-ify libempathy-gtk. Actually most window/dialog do not inherit from GtkWindow/GtkDialog. Need to create a glade catalog.
- Filter channels before dispatching them. For example we need a GtkStatusIcon that blink when an event arrives (text/voip/ft channel) and tells the MC to dispatch the channel only when the user clicked the icon. Like in gossip. For that we need a filter DBus API in MC, not yet written, a draft spec is proposed on the telepathy ML.
- Make use of NetworkManager to set the presence
- Remove Quit option everywhere, empathy is a session service and shouldn't be leaved.
- Add sound events
- Add register capability in GossipAccountsDialog if the profile says it's supported.
+ - Write a manual based on gossip's.
- Testing and Bugfixing.
+ - Update translations.
SoC projects:
- Adding VoIP support based on the patch proposed for gossip.
diff --git a/data/jabber.profile b/data/jabber.profile
index 55a1e6978..c91691daa 100644
--- a/data/jabber.profile
+++ b/data/jabber.profile
@@ -9,4 +9,5 @@ DefaultAccountDomain = jabber.org
SupportsInvisible = 0
VCardField = X-Jabber
VCardDefault = true
+Default-ignore-ssl-errors = 1
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__ */
diff --git a/libempathy/empathy-log-manager.c b/libempathy/empathy-log-manager.c
index ca5297ea7..49c67ec4e 100644
--- a/libempathy/empathy-log-manager.c
+++ b/libempathy/empathy-log-manager.c
@@ -39,6 +39,7 @@
#define LOG_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR)
#define LOG_FILE_CREATE_MODE (S_IRUSR | S_IWUSR)
+#define LOG_DIR_CHATROOMS "chatrooms"
#define LOG_FILENAME_SUFFIX ".log"
#define LOG_TIME_FORMAT_FULL "%Y%m%dT%H:%M:%S"
#define LOG_TIME_FORMAT "%Y%m%d"
@@ -51,21 +52,35 @@
"</log>\n"
struct _EmpathyLogManagerPriv {
- gboolean dummy;
+ gchar *basedir;
};
-static void empathy_log_manager_class_init (EmpathyLogManagerClass *klass);
-static void empathy_log_manager_init (EmpathyLogManager *manager);
-static void log_manager_finalize (GObject *object);
-static gchar * log_manager_get_dir (McAccount *account,
- const gchar *chat_id);
-static gchar * log_manager_get_filename (McAccount *account,
- const gchar *chat_id);
-static gchar * log_manager_get_filename_for_date (McAccount *account,
- const gchar *chat_id,
- const gchar *date);
-static gchar * log_manager_get_timestamp_filename (void);
-static gchar * log_manager_get_timestamp_from_message (GossipMessage *message);
+static void empathy_log_manager_class_init (EmpathyLogManagerClass *klass);
+static void empathy_log_manager_init (EmpathyLogManager *manager);
+static void log_manager_finalize (GObject *object);
+static const gchar * log_manager_get_basedir (EmpathyLogManager *manager);
+static GList * log_manager_get_all_files (EmpathyLogManager *manager,
+ const gchar *dir);
+static GList * log_manager_get_chats (EmpathyLogManager *manager,
+ const gchar *dir,
+ gboolean is_chatroom);
+static gchar * log_manager_get_dir (EmpathyLogManager *manager,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom);
+static gchar * log_manager_get_filename (EmpathyLogManager *manager,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom);
+static gchar * log_manager_get_filename_for_date (EmpathyLogManager *manager,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom,
+ const gchar *date);
+static gchar * log_manager_get_timestamp_filename (void);
+static gchar * log_manager_get_timestamp_from_message (GossipMessage *message);
+static EmpathyLogSearchHit *log_manager_search_hit_new (EmpathyLogManager *manager,
+ const gchar *filename);
G_DEFINE_TYPE (EmpathyLogManager, empathy_log_manager, G_TYPE_OBJECT);
@@ -87,6 +102,11 @@ empathy_log_manager_init (EmpathyLogManager *manager)
static void
log_manager_finalize (GObject *object)
{
+ EmpathyLogManagerPriv *priv;
+
+ priv = GET_PRIV (object);
+
+ g_free (priv->basedir);
}
EmpathyLogManager *
@@ -107,6 +127,7 @@ empathy_log_manager_new (void)
void
empathy_log_manager_add_message (EmpathyLogManager *manager,
const gchar *chat_id,
+ gboolean chatroom,
GossipMessage *message)
{
FILE *file;
@@ -132,7 +153,7 @@ empathy_log_manager_add_message (EmpathyLogManager *manager,
return;
}
- filename = log_manager_get_filename (account, chat_id);
+ filename = log_manager_get_filename (manager, account, chat_id, chatroom);
gossip_debug (DEBUG_DOMAIN, "Adding message: '%s' to file: '%s'",
body_str, filename);
@@ -154,24 +175,17 @@ empathy_log_manager_add_message (EmpathyLogManager *manager,
timestamp = log_manager_get_timestamp_from_message (message);
str = gossip_contact_get_name (sender);
- if (!str) {
- contact_name = g_strdup ("");
- } else {
- contact_name = g_markup_escape_text (str, -1);
- }
+ contact_name = g_markup_escape_text (str, -1);
str = gossip_contact_get_id (sender);
- if (!str) {
- contact_id = g_strdup ("");
- } else {
- contact_id = g_markup_escape_text (str, -1);
- }
+ contact_id = g_markup_escape_text (str, -1);
g_fprintf (file,
- "<message time='%s' id='%s' name='%s'>%s</message>\n" LOG_FOOTER,
+ "<message time='%s' id='%s' name='%s' isuser='%s'>%s</message>\n" LOG_FOOTER,
timestamp,
contact_id,
contact_name,
+ gossip_contact_is_user (sender) ? "true" : "false",
body);
fclose (file);
@@ -185,7 +199,8 @@ empathy_log_manager_add_message (EmpathyLogManager *manager,
GList *
empathy_log_manager_get_dates (EmpathyLogManager *manager,
McAccount *account,
- const gchar *chat_id)
+ const gchar *chat_id,
+ gboolean chatroom)
{
GList *dates = NULL;
gchar *date;
@@ -198,7 +213,7 @@ empathy_log_manager_get_dates (EmpathyLogManager *manager,
g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
g_return_val_if_fail (chat_id != NULL, NULL);
- directory = log_manager_get_dir (account, chat_id);
+ directory = log_manager_get_dir (manager, account, chat_id, chatroom);
if (!directory) {
return NULL;
}
@@ -238,6 +253,7 @@ GList *
empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
McAccount *account,
const gchar *chat_id,
+ gboolean chatroom,
const gchar *date)
{
gchar *filename;
@@ -251,7 +267,7 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
g_return_val_if_fail (chat_id != NULL, NULL);
- filename = log_manager_get_filename_for_date (account, chat_id, date);
+ filename = log_manager_get_filename_for_date (manager, account, chat_id, chatroom, date);
gossip_debug (DEBUG_DOMAIN, "Attempting to parse filename:'%s'...", filename);
@@ -291,6 +307,8 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
gchar *sender_id;
gchar *sender_name;
gchar *body;
+ gchar *is_user_str;
+ gboolean is_user = FALSE;
if (strcmp (node->name, "message") != 0) {
continue;
@@ -300,10 +318,16 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
time = xmlGetProp (node, "time");
sender_id = xmlGetProp (node, "id");
sender_name = xmlGetProp (node, "name");
+ is_user_str = xmlGetProp (node, "isuser");
+
+ if (is_user_str) {
+ is_user = strcmp (is_user_str, "true") == 0;
+ }
t = gossip_time_parse (time);
sender = gossip_contact_new_full (account, sender_id, sender_name);
+ gossip_contact_set_is_user (sender, is_user);
message = gossip_message_new (body);
gossip_message_set_sender (message, sender);
gossip_message_set_timestamp (message, t);
@@ -329,7 +353,8 @@ empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
GList *
empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
McAccount *account,
- const gchar *chat_id)
+ const gchar *chat_id,
+ gboolean chatroom)
{
GList *messages = NULL;
GList *dates;
@@ -339,13 +364,14 @@ empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
g_return_val_if_fail (chat_id != NULL, NULL);
- dates = empathy_log_manager_get_dates (manager, account, chat_id);
+ dates = empathy_log_manager_get_dates (manager, account, chat_id, chatroom);
l = g_list_last (dates);
if (l) {
messages = empathy_log_manager_get_messages_for_date (manager,
account,
chat_id,
+ chatroom,
l->data);
}
@@ -355,22 +381,238 @@ empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
return messages;
}
+GList *
+empathy_log_manager_get_chats (EmpathyLogManager *manager,
+ McAccount *account)
+{
+ const gchar *basedir;
+ gchar *dir;
+
+ basedir = log_manager_get_basedir (manager);
+ dir = g_build_filename (basedir,
+ mc_account_get_unique_name (account),
+ NULL);
+
+ return log_manager_get_chats (manager, dir, FALSE);
+}
+
+GList *
+empathy_log_manager_search_new (EmpathyLogManager *manager,
+ const gchar *text)
+{
+ GList *files, *l;
+ GList *hits = NULL;
+ gchar *text_casefold;
+
+ g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
+ g_return_val_if_fail (!G_STR_EMPTY (text), NULL);
+
+ text_casefold = g_utf8_casefold (text, -1);
+
+ files = log_manager_get_all_files (manager, NULL);
+ gossip_debug (DEBUG_DOMAIN, "Found %d log files in total",
+ g_list_length (files));
+
+ for (l = files; l; l = l->next) {
+ gchar *filename;
+ GMappedFile *file;
+ gsize length;
+ gchar *contents;
+ gchar *contents_casefold;
+
+ filename = l->data;
+
+ file = g_mapped_file_new (filename, FALSE, NULL);
+ if (!file) {
+ continue;
+ }
+
+ length = g_mapped_file_get_length (file);
+ contents = g_mapped_file_get_contents (file);
+ contents_casefold = g_utf8_casefold (contents, length);
+
+ g_mapped_file_free (file);
+
+ if (strstr (contents_casefold, text_casefold)) {
+ EmpathyLogSearchHit *hit;
+
+ hit = log_manager_search_hit_new (manager, filename);
+
+ if (hit) {
+ hits = g_list_prepend (hits, hit);
+ gossip_debug (DEBUG_DOMAIN,
+ "Found text:'%s' in file:'%s' on date:'%s'...",
+ text, hit->filename, hit->date);
+ }
+ }
+
+ g_free (contents_casefold);
+ g_free (filename);
+ }
+ g_list_free (files);
+
+ g_free (text_casefold);
+
+ return hits;
+}
+
+void
+empathy_log_manager_search_free (GList *hits)
+{
+ GList *l;
+ EmpathyLogSearchHit *hit;
+
+ for (l = hits; l; l = l->next) {
+ hit = l->data;
+
+ if (hit->account) {
+ g_object_unref (hit->account);
+ }
+
+ g_free (hit->date);
+ g_free (hit->filename);
+ g_free (hit->chat_id);
+
+ g_slice_free (EmpathyLogSearchHit, hit);
+ }
+
+ g_list_free (hits);
+}
+
+/* Format is just date, 20061201. */
+gchar *
+empathy_log_manager_get_date_readable (const gchar *date)
+{
+ GossipTime t;
+
+ t = gossip_time_parse (date);
+
+ return gossip_time_to_string_local (t, "%a %d %b %Y");
+}
+
+static const gchar *
+log_manager_get_basedir (EmpathyLogManager *manager)
+{
+ EmpathyLogManagerPriv *priv;
+
+ priv = GET_PRIV (manager);
+
+ if (priv->basedir) {
+ return priv->basedir;
+ }
+
+ priv->basedir = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_home_dir (),
+ ".gnome2",
+ PACKAGE_NAME,
+ "logs",
+ NULL);
+
+ return priv->basedir;
+}
+
+static GList *
+log_manager_get_all_files (EmpathyLogManager *manager,
+ const gchar *dir)
+{
+ GDir *gdir;
+ GList *files = NULL;
+ const gchar *name;
+
+ if (!dir) {
+ dir = log_manager_get_basedir (manager);
+ }
+
+ gdir = g_dir_open (dir, 0, NULL);
+ if (!gdir) {
+ return NULL;
+ }
+
+ while ((name = g_dir_read_name (gdir)) != NULL) {
+ gchar *filename;
+
+ filename = g_build_filename (dir, name, NULL);
+ if (g_str_has_suffix (filename, LOG_FILENAME_SUFFIX)) {
+ files = g_list_prepend (files, filename);
+ continue;
+ }
+
+ if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
+ /* Recursively get all log files */
+ files = g_list_concat (files, log_manager_get_all_files (manager, filename));
+ }
+ g_free (filename);
+ }
+
+ g_dir_close (gdir);
+
+ return files;
+}
+
+static GList *
+log_manager_get_chats (EmpathyLogManager *manager,
+ const gchar *dir,
+ gboolean is_chatroom)
+{
+ GDir *gdir;
+ GList *hits = NULL;
+ const gchar *name;
+
+ gdir = g_dir_open (dir, 0, NULL);
+ if (!gdir) {
+ return NULL;
+ }
+
+ while ((name = g_dir_read_name (gdir)) != NULL) {
+ EmpathyLogSearchHit *hit;
+ gchar *filename;
+
+ filename = g_build_filename (dir, name, NULL);
+ if (strcmp (name, LOG_DIR_CHATROOMS) == 0) {
+ hits = g_list_concat (hits, log_manager_get_chats (manager, filename, TRUE));
+ g_free (filename);
+ continue;
+ }
+
+ hit = g_slice_new0 (EmpathyLogSearchHit);
+ hit->chat_id = g_strdup (name);
+ hit->is_chatroom = is_chatroom;
+
+ hits = g_list_prepend (hits, hit);
+ }
+
+ g_dir_close (gdir);
+
+ return hits;
+}
+
static gchar *
-log_manager_get_dir (McAccount *account,
- const gchar *chat_id)
+log_manager_get_dir (EmpathyLogManager *manager,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom)
{
const gchar *account_id;
gchar *basedir;
+ gchar *str;
account_id = mc_account_get_unique_name (account);
- basedir = g_build_path (G_DIR_SEPARATOR_S,
- g_get_home_dir (),
- ".gnome2",
- PACKAGE_NAME,
- "logs",
- account_id,
- chat_id,
- NULL);
+ basedir =
+ str = g_build_path (G_DIR_SEPARATOR_S,
+ log_manager_get_basedir (manager),
+ account_id,
+ chat_id,
+ NULL);
+
+ if (chatroom) {
+ basedir = g_build_path (G_DIR_SEPARATOR_S,
+ str,
+ LOG_DIR_CHATROOMS,
+ NULL);
+ g_free (str);
+ } else {
+ basedir = str;
+ }
if (!g_file_test (basedir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
gossip_debug (DEBUG_DOMAIN, "Creating directory:'%s'", basedir);
@@ -382,14 +624,16 @@ log_manager_get_dir (McAccount *account,
}
static gchar *
-log_manager_get_filename (McAccount *account,
- const gchar *chat_id)
+log_manager_get_filename (EmpathyLogManager *manager,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom)
{
gchar *basedir;
gchar *timestamp;
gchar *filename;
- basedir = log_manager_get_dir (account, chat_id);
+ basedir = log_manager_get_dir (manager, account, chat_id, chatroom);
timestamp = log_manager_get_timestamp_filename ();
filename = g_build_filename (basedir, timestamp, NULL);
@@ -400,15 +644,17 @@ log_manager_get_filename (McAccount *account,
}
static gchar *
-log_manager_get_filename_for_date (McAccount *account,
- const gchar *chat_id,
- const gchar *date)
+log_manager_get_filename_for_date (EmpathyLogManager *manager,
+ McAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom,
+ const gchar *date)
{
gchar *basedir;
gchar *timestamp;
gchar *filename;
- basedir = log_manager_get_dir (account, chat_id);
+ basedir = log_manager_get_dir (manager, account, chat_id, chatroom);
timestamp = g_strconcat (date, LOG_FILENAME_SUFFIX, NULL);
filename = g_build_filename (basedir, timestamp, NULL);
@@ -445,3 +691,39 @@ log_manager_get_timestamp_from_message (GossipMessage *message)
return gossip_time_to_string_utc (t, LOG_TIME_FORMAT_FULL);
}
+static EmpathyLogSearchHit *
+log_manager_search_hit_new (EmpathyLogManager *manager,
+ const gchar *filename)
+{
+ EmpathyLogSearchHit *hit;
+ const gchar *account_name;
+ const gchar *end;
+ gchar **strv;
+ guint len;
+
+ if (!g_str_has_suffix (filename, LOG_FILENAME_SUFFIX)) {
+ return NULL;
+ }
+
+ strv = g_strsplit (filename, G_DIR_SEPARATOR_S, -1);
+ len = g_strv_length (strv);
+
+ hit = g_slice_new0 (EmpathyLogSearchHit);
+
+ end = strstr (strv[len-1], LOG_FILENAME_SUFFIX);
+ hit->date = g_strndup (strv[len-1], end - strv[len-1]);
+ hit->chat_id = g_strdup (strv[len-2]);
+ hit->is_chatroom = (strcmp (strv[len-3], LOG_DIR_CHATROOMS) == 0);
+ if (hit->is_chatroom) {
+ account_name = strv[len-4];
+ } else {
+ account_name = strv[len-3];
+ }
+ hit->account = mc_account_lookup (account_name);
+ hit->filename = g_strdup (filename);
+
+ g_strfreev (strv);
+
+ return hit;
+}
+
diff --git a/libempathy/empathy-log-manager.h b/libempathy/empathy-log-manager.h
index 8df68d5ed..9a163fd36 100644
--- a/libempathy/empathy-log-manager.h
+++ b/libempathy/empathy-log-manager.h
@@ -41,6 +41,7 @@ G_BEGIN_DECLS
typedef struct _EmpathyLogManager EmpathyLogManager;
typedef struct _EmpathyLogManagerClass EmpathyLogManagerClass;
typedef struct _EmpathyLogManagerPriv EmpathyLogManagerPriv;
+typedef struct _EmpathyLogSearchHit EmpathyLogSearchHit;
struct _EmpathyLogManager {
GObject parent;
@@ -50,21 +51,39 @@ struct _EmpathyLogManagerClass {
GObjectClass parent_class;
};
+struct _EmpathyLogSearchHit {
+ McAccount *account;
+ gchar *chat_id;
+ gboolean is_chatroom;
+ gchar *filename;
+ gchar *date;
+};
+
GType empathy_log_manager_get_type (void) G_GNUC_CONST;
EmpathyLogManager *empathy_log_manager_new (void);
void empathy_log_manager_add_message (EmpathyLogManager *manager,
const gchar *chat_id,
+ gboolean chatroom,
GossipMessage *message);
GList * empathy_log_manager_get_dates (EmpathyLogManager *manager,
McAccount *account,
- const gchar *chat_id);
+ const gchar *chat_id,
+ gboolean chatroom);
GList * empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
McAccount *account,
const gchar *chat_id,
+ gboolean chatroom,
const gchar *date);
GList * empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
McAccount *account,
- const gchar *chat_id);
+ const gchar *chat_id,
+ gboolean chatroom);
+GList * empathy_log_manager_get_chats (EmpathyLogManager *manager,
+ McAccount *account);
+GList * empathy_log_manager_search_new (EmpathyLogManager *manager,
+ const gchar *text);
+void empathy_log_manager_search_free (GList *hits);
+gchar * empathy_log_manager_get_date_readable (const gchar *date);
G_END_DECLS
diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c
index d63e82551..a2852e1d8 100644
--- a/libempathy/empathy-tp-chat.c
+++ b/libempathy/empathy-tp-chat.c
@@ -790,12 +790,13 @@ tp_chat_emit_message (EmpathyTpChat *chat,
EmpathyTpChatPriv *priv;
GossipMessage *message;
GossipContact *sender;
+ GossipContact *receiver;
priv = GET_PRIV (chat);
+ receiver = empathy_tp_contact_list_get_user (priv->list);
if (from_handle == 0) {
- sender = empathy_tp_contact_list_get_user (priv->list);
- g_object_ref (sender);
+ sender = g_object_ref (receiver);
} else {
sender = empathy_tp_contact_list_get_from_handle (priv->list,
from_handle);
@@ -804,6 +805,7 @@ tp_chat_emit_message (EmpathyTpChat *chat,
message = gossip_message_new (message_body);
gossip_message_set_type (message, type);
gossip_message_set_sender (message, sender);
+ gossip_message_set_receiver (message, receiver);
gossip_message_set_timestamp (message, (GossipTime) timestamp);
g_signal_emit (chat, signals[MESSAGE_RECEIVED], 0, message);
diff --git a/libempathy/empathy-tp-contact-list.c b/libempathy/empathy-tp-contact-list.c
index c81279043..b696e990c 100644
--- a/libempathy/empathy-tp-contact-list.c
+++ b/libempathy/empathy-tp-contact-list.c
@@ -380,8 +380,8 @@ empathy_tp_contact_list_new (McAccount *account)
error ? error->message : "No error given");
g_clear_error (&error);
} else {
- /* FIXME: this adds the handle to the roster */
priv->user_contact = empathy_tp_contact_list_get_from_handle (list, handle);
+ gossip_contact_set_is_user (priv->user_contact, TRUE);
}
return list;
@@ -1276,6 +1276,10 @@ tp_contact_list_name_updated_cb (GossipContact *contact,
priv = GET_PRIV (list);
+ if (!priv->aliasing_iface) {
+ return;
+ }
+
handle = gossip_contact_get_handle (contact);
new_name = gossip_contact_get_name (contact);
diff --git a/libempathy/gossip-contact.c b/libempathy/gossip-contact.c
index 82147f67e..53fe7e182 100644
--- a/libempathy/gossip-contact.c
+++ b/libempathy/gossip-contact.c
@@ -30,7 +30,6 @@
#include "gossip-contact.h"
#include "gossip-utils.h"
#include "gossip-debug.h"
-#include "empathy-contact-manager.h"
#define DEBUG_DOMAIN "Contact"
@@ -47,6 +46,7 @@ struct _GossipContactPriv {
GList *groups;
GossipSubscription subscription;
guint handle;
+ gboolean is_user;
};
static void contact_class_init (GossipContactClass *class);
@@ -70,7 +70,8 @@ enum {
PROP_PRESENCE,
PROP_GROUPS,
PROP_SUBSCRIPTION,
- PROP_HANDLE
+ PROP_HANDLE,
+ PROP_IS_USER
};
static gpointer parent_class = NULL;
@@ -180,6 +181,13 @@ contact_class_init (GossipContactClass *class)
G_MAXUINT,
0,
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_IS_USER,
+ g_param_spec_boolean ("is-user",
+ "Contact is-user",
+ "Is contact the user",
+ FALSE,
+ G_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GossipContactPriv));
}
@@ -187,17 +195,6 @@ contact_class_init (GossipContactClass *class)
static void
contact_init (GossipContact *contact)
{
- GossipContactPriv *priv;
-
- priv = GET_PRIV (contact);
-
- priv->id = NULL;
- priv->name = NULL;
- priv->avatar = NULL;
- priv->account = NULL;
- priv->presence = NULL;
- priv->groups = NULL;
- priv->handle = 0;
}
static void
@@ -269,6 +266,9 @@ contact_get_property (GObject *object,
case PROP_HANDLE:
g_value_set_uint (value, priv->handle);
break;
+ case PROP_IS_USER:
+ g_value_set_boolean (value, priv->is_user);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -318,6 +318,10 @@ contact_set_property (GObject *object,
gossip_contact_set_handle (GOSSIP_CONTACT (object),
g_value_get_uint (value));
break;
+ case PROP_IS_USER:
+ gossip_contact_set_is_user (GOSSIP_CONTACT (object),
+ g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -449,6 +453,18 @@ gossip_contact_get_handle (GossipContact *contact)
return priv->handle;
}
+gboolean
+gossip_contact_is_user (GossipContact *contact)
+{
+ GossipContactPriv *priv;
+
+ g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE);
+
+ priv = GET_PRIV (contact);
+
+ return priv->is_user;
+}
+
void
gossip_contact_set_id (GossipContact *contact,
const gchar *id)
@@ -630,6 +646,25 @@ gossip_contact_set_handle (GossipContact *contact,
}
void
+gossip_contact_set_is_user (GossipContact *contact,
+ gboolean is_user)
+{
+ GossipContactPriv *priv;
+
+ g_return_if_fail (GOSSIP_IS_CONTACT (contact));
+
+ priv = GET_PRIV (contact);
+
+ if (priv->is_user == is_user) {
+ return;
+ }
+
+ priv->is_user = is_user;
+
+ g_object_notify (G_OBJECT (contact), "is-user");
+}
+
+void
gossip_contact_add_group (GossipContact *contact,
const gchar *group)
{
@@ -722,24 +757,6 @@ gossip_contact_get_status (GossipContact *contact)
return gossip_presence_state_get_default_status (MC_PRESENCE_OFFLINE);
}
-GossipContact *
-gossip_contact_get_user (GossipContact *contact)
-{
- GossipContactPriv *priv;
- EmpathyContactManager *manager;
- GossipContact *user_contact;
-
- g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
-
- priv = GET_PRIV (contact);
-
- manager = empathy_contact_manager_new ();
- user_contact = empathy_contact_manager_get_user (manager, priv->account);
- g_object_unref (manager);
-
- return user_contact;
-}
-
gboolean
gossip_contact_equal (gconstpointer v1,
gconstpointer v2)
diff --git a/libempathy/gossip-contact.h b/libempathy/gossip-contact.h
index 23da37538..14b32fdc2 100644
--- a/libempathy/gossip-contact.h
+++ b/libempathy/gossip-contact.h
@@ -69,6 +69,7 @@ GossipPresence * gossip_contact_get_presence (GossipContact
GList * gossip_contact_get_groups (GossipContact *contact);
GossipSubscription gossip_contact_get_subscription (GossipContact *contact);
guint gossip_contact_get_handle (GossipContact *contact);
+gboolean gossip_contact_is_user (GossipContact *contact);
void gossip_contact_set_id (GossipContact *contact,
const gchar *id);
void gossip_contact_set_name (GossipContact *contact,
@@ -85,6 +86,8 @@ void gossip_contact_set_subscription (GossipContact
GossipSubscription subscription);
void gossip_contact_set_handle (GossipContact *contact,
guint handle);
+void gossip_contact_set_is_user (GossipContact *contact,
+ gboolean is_user);
void gossip_contact_add_group (GossipContact *contact,
const gchar *group);
void gossip_contact_remove_group (GossipContact *contact,
@@ -93,7 +96,6 @@ gboolean gossip_contact_is_online (GossipContact
gboolean gossip_contact_is_in_group (GossipContact *contact,
const gchar *group);
const gchar * gossip_contact_get_status (GossipContact *contact);
-GossipContact * gossip_contact_get_user (GossipContact *contact);
gboolean gossip_contact_equal (gconstpointer v1,
gconstpointer v2);
guint gossip_contact_hash (gconstpointer key);
diff --git a/libempathy/gossip-message.c b/libempathy/gossip-message.c
index c4844e655..a46a2a5dc 100644
--- a/libempathy/gossip-message.c
+++ b/libempathy/gossip-message.c
@@ -33,6 +33,7 @@ typedef struct _GossipMessagePriv GossipMessagePriv;
struct _GossipMessagePriv {
GossipMessageType type;
GossipContact *sender;
+ GossipContact *receiver;
gchar *body;
GossipTime timestamp;
@@ -54,6 +55,7 @@ enum {
PROP_0,
PROP_TYPE,
PROP_SENDER,
+ PROP_RECEIVER,
PROP_BODY,
PROP_TIMESTAMP,
};
@@ -114,7 +116,13 @@ gossip_message_class_init (GossipMessageClass *class)
"The sender of the message",
GOSSIP_TYPE_CONTACT,
G_PARAM_READWRITE));
-
+ g_object_class_install_property (object_class,
+ PROP_RECEIVER,
+ g_param_spec_object ("receiver",
+ "Message Receiver",
+ "The receiver of the message",
+ GOSSIP_TYPE_CONTACT,
+ G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_BODY,
g_param_spec_string ("body",
@@ -144,9 +152,6 @@ gossip_message_init (GossipMessage *message)
priv = GET_PRIV (message);
- priv->type = GOSSIP_MESSAGE_TYPE_NORMAL;
- priv->sender = NULL;
- priv->body = NULL;
priv->timestamp = gossip_time_get_current ();
}
@@ -160,6 +165,9 @@ gossip_message_finalize (GObject *object)
if (priv->sender) {
g_object_unref (priv->sender);
}
+ if (priv->receiver) {
+ g_object_unref (priv->receiver);
+ }
g_free (priv->body);
@@ -183,6 +191,9 @@ message_get_property (GObject *object,
case PROP_SENDER:
g_value_set_object (value, priv->sender);
break;
+ case PROP_RECEIVER:
+ g_value_set_object (value, priv->receiver);
+ break;
case PROP_BODY:
g_value_set_string (value, priv->body);
break;
@@ -211,6 +222,10 @@ message_set_property (GObject *object,
gossip_message_set_sender (GOSSIP_MESSAGE (object),
GOSSIP_CONTACT (g_value_get_object (value)));
break;
+ case PROP_RECEIVER:
+ gossip_message_set_receiver (GOSSIP_MESSAGE (object),
+ GOSSIP_CONTACT (g_value_get_object (value)));
+ break;
case PROP_BODY:
gossip_message_set_body (GOSSIP_MESSAGE (object),
g_value_get_string (value));
@@ -290,6 +305,39 @@ gossip_message_set_sender (GossipMessage *message, GossipContact *contact)
g_object_notify (G_OBJECT (message), "sender");
}
+GossipContact *
+gossip_message_get_receiver (GossipMessage *message)
+{
+ GossipMessagePriv *priv;
+
+ g_return_val_if_fail (GOSSIP_IS_MESSAGE (message), NULL);
+
+ priv = GET_PRIV (message);
+
+ return priv->receiver;
+}
+
+void
+gossip_message_set_receiver (GossipMessage *message, GossipContact *contact)
+{
+ GossipMessagePriv *priv;
+ GossipContact *old_receiver;
+
+ g_return_if_fail (GOSSIP_IS_MESSAGE (message));
+ g_return_if_fail (GOSSIP_IS_CONTACT (contact));
+
+ priv = GET_PRIV (message);
+
+ old_receiver = priv->receiver;
+ priv->receiver = g_object_ref (contact);
+
+ if (old_receiver) {
+ g_object_unref (old_receiver);
+ }
+
+ g_object_notify (G_OBJECT (message), "receiver");
+}
+
const gchar *
gossip_message_get_body (GossipMessage *message)
{
diff --git a/libempathy/gossip-message.h b/libempathy/gossip-message.h
index 770ecfe1b..aa4948025 100644
--- a/libempathy/gossip-message.h
+++ b/libempathy/gossip-message.h
@@ -66,6 +66,9 @@ void gossip_message_set_type (GossipMessage *
GossipContact * gossip_message_get_sender (GossipMessage *message);
void gossip_message_set_sender (GossipMessage *message,
GossipContact *contact);
+GossipContact * gossip_message_get_receiver (GossipMessage *message);
+void gossip_message_set_receiver (GossipMessage *message,
+ GossipContact *contact);
const gchar * gossip_message_get_body (GossipMessage *message);
void gossip_message_set_body (GossipMessage *message,
const gchar *body);
diff --git a/src/empathy-main.c b/src/empathy-main.c
index f64b2d6e9..92a66b2c8 100644
--- a/src/empathy-main.c
+++ b/src/empathy-main.c
@@ -127,6 +127,7 @@ main (int argc, char *argv[])
0, G_OPTION_ARG_NONE, &no_connect,
N_("Don't connect on startup"),
NULL },
+ { NULL }
};
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);