aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>2011-04-28 01:17:31 +0800
committerEmilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>2011-04-28 01:17:31 +0800
commit7b3b4eeffb16c4c57a02706e336f645dea1ea036 (patch)
treeffa280b1b99fd8b058fecbdff63cb1c6d6944c88
parentfe699e07fe13a703c8278775f1445c754b6a7bc6 (diff)
parentea8d261e1ec69ee73f0f77ddff1a43146d7d4e63 (diff)
downloadgsoc2013-empathy-7b3b4eeffb16c4c57a02706e336f645dea1ea036.tar
gsoc2013-empathy-7b3b4eeffb16c4c57a02706e336f645dea1ea036.tar.gz
gsoc2013-empathy-7b3b4eeffb16c4c57a02706e336f645dea1ea036.tar.bz2
gsoc2013-empathy-7b3b4eeffb16c4c57a02706e336f645dea1ea036.tar.lz
gsoc2013-empathy-7b3b4eeffb16c4c57a02706e336f645dea1ea036.tar.xz
gsoc2013-empathy-7b3b4eeffb16c4c57a02706e336f645dea1ea036.tar.zst
gsoc2013-empathy-7b3b4eeffb16c4c57a02706e336f645dea1ea036.zip
Merge branch 'empathy-skype' into debian
-rw-r--r--configure.ac3
-rw-r--r--libempathy-gtk/empathy-account-chooser.c17
-rw-r--r--libempathy-gtk/empathy-account-chooser.h3
-rw-r--r--libempathy-gtk/empathy-images.h4
-rw-r--r--libempathy-gtk/empathy-log-window.c3751
-rw-r--r--libempathy-gtk/empathy-log-window.h12
-rw-r--r--libempathy-gtk/empathy-log-window.ui429
-rw-r--r--libempathy/Makefile.am2
-rw-r--r--libempathy/action-chain-internal.h51
-rw-r--r--libempathy/action-chain.c192
-rw-r--r--libempathy/empathy-message.c54
-rw-r--r--libempathy/empathy-utils.c91
-rw-r--r--libempathy/empathy-utils.h31
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/empathy-main-window.c48
15 files changed, 3122 insertions, 1567 deletions
diff --git a/configure.ac b/configure.ac
index 6986cd6a7..86d6b805f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,8 +59,11 @@ GNOME_CONTROL_CENTER_GTK3_REQUIRED=2.31.4
# telepathy-yell
prev_top_build_prefix=$ac_top_build_prefix
+prev_ac_configure_args=$ac_configure_args
+ac_configure_args="$ac_configure_args --disable-shared-library"
AX_CONFIG_DIR([telepathy-yell])
ac_top_build_prefix=$prev_top_build_prefix
+ac_configure_args=$prev_ac_configure_args
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:"$ac_top_build_prefix"telepathy-yell/telepathy-yell
AC_CONFIG_MACRO_DIR([m4])
diff --git a/libempathy-gtk/empathy-account-chooser.c b/libempathy-gtk/empathy-account-chooser.c
index b7eebe587..afb9841e1 100644
--- a/libempathy-gtk/empathy-account-chooser.c
+++ b/libempathy-gtk/empathy-account-chooser.c
@@ -700,8 +700,15 @@ account_chooser_find_account_foreach (GtkTreeModel *model,
{
FindAccountData *data = user_data;
TpAccount *account;
+ RowType type;
- gtk_tree_model_get (model, iter, COL_ACCOUNT_POINTER, &account, -1);
+ gtk_tree_model_get (model, iter,
+ COL_ACCOUNT_POINTER, &account,
+ COL_ACCOUNT_ROW_TYPE, &type,
+ -1);
+
+ if (type != ROW_ACCOUNT)
+ return FALSE;
if (account == data->account) {
data->found = TRUE;
@@ -984,3 +991,11 @@ empathy_account_chooser_get_account (EmpathyAccountChooser *chooser)
return account;
}
+
+TpAccountManager *
+empathy_account_chooser_get_account_manager (EmpathyAccountChooser *self)
+{
+ EmpathyAccountChooserPriv *priv = GET_PRIV (self);
+
+ return priv->manager;
+}
diff --git a/libempathy-gtk/empathy-account-chooser.h b/libempathy-gtk/empathy-account-chooser.h
index 08141f497..c9e69b4f6 100644
--- a/libempathy-gtk/empathy-account-chooser.h
+++ b/libempathy-gtk/empathy-account-chooser.h
@@ -27,7 +27,7 @@
#include <gtk/gtk.h>
-#include <telepathy-glib/account.h>
+#include <telepathy-glib/telepathy-glib.h>
G_BEGIN_DECLS
@@ -81,6 +81,7 @@ TpAccount * empathy_account_chooser_get_account (EmpathyAccountChooser
TpConnection * empathy_account_chooser_get_connection (EmpathyAccountChooser *chooser);
gboolean empathy_account_chooser_set_account (EmpathyAccountChooser *chooser,
TpAccount *account);
+TpAccountManager * empathy_account_chooser_get_account_manager (EmpathyAccountChooser *self);
gboolean empathy_account_chooser_get_has_all_option (EmpathyAccountChooser *chooser);
void empathy_account_chooser_set_has_all_option (EmpathyAccountChooser *chooser,
gboolean has_all_option);
diff --git a/libempathy-gtk/empathy-images.h b/libempathy-gtk/empathy-images.h
index 86f1db641..e2512d495 100644
--- a/libempathy-gtk/empathy-images.h
+++ b/libempathy-gtk/empathy-images.h
@@ -47,6 +47,10 @@ G_BEGIN_DECLS
#define EMPATHY_IMAGE_DOCUMENT_SEND "document-send"
#define EMPATHY_IMAGE_AVATAR_DEFAULT "avatar-default"
+#define EMPATHY_IMAGE_CALL_MISSED "call-start"
+#define EMPATHY_IMAGE_CALL_INCOMING "call-start"
+#define EMPATHY_IMAGE_CALL_OUTGOING "call-stop"
+
G_END_DECLS
#endif /* __EMPATHY_IMAGES_ICONS_H__ */
diff --git a/libempathy-gtk/empathy-log-window.c b/libempathy-gtk/empathy-log-window.c
index f6b5edf16..d3aa07027 100644
--- a/libempathy-gtk/empathy-log-window.c
+++ b/libempathy-gtk/empathy-log-window.c
@@ -1,7 +1,6 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2006-2007 Imendio AB
- * Copyright (C) 2007-2008 Collabora Ltd.
+ * Copyright (C) 2007-2011 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
@@ -20,6 +19,7 @@
*
* Authors: Martyn Russell <martyn@imendio.com>
* Xavier Claessens <xclaesse@gmail.com>
+ * Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
*/
#include "config.h"
@@ -30,13 +30,15 @@
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
-#include <telepathy-glib/account-manager.h>
+#include <telepathy-glib/telepathy-glib.h>
#include <telepathy-glib/proxy-subclass.h>
-#include <telepathy-logger/log-manager.h>
+#include <telepathy-logger/telepathy-logger.h>
+#include <telepathy-logger/call-event.h>
#include <extensions/extensions.h>
+#include <libempathy/action-chain-internal.h>
#include <libempathy/empathy-chatroom-manager.h>
#include <libempathy/empathy-chatroom.h>
#include <libempathy/empathy-message.h>
@@ -45,1511 +47,2792 @@
#include "empathy-log-window.h"
#include "empathy-account-chooser.h"
+#include "empathy-call-utils.h"
#include "empathy-chat-view.h"
+#include "empathy-contact-dialogs.h"
+#include "empathy-images.h"
#include "empathy-theme-manager.h"
#include "empathy-ui-utils.h"
#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
#include <libempathy/empathy-debug.h>
-typedef struct {
- GtkWidget *window;
-
- GtkWidget *notebook;
-
- GtkWidget *entry_find;
- GtkWidget *button_find;
- GtkWidget *treeview_find;
- GtkWidget *scrolledwindow_find;
- EmpathyChatView *chatview_find;
- GtkWidget *button_previous;
- GtkWidget *button_next;
-
- GtkWidget *hbox_chats;
- GtkWidget *account_chooser_chats;
- GtkWidget *entry_chats;
- GtkWidget *calendar_chats;
- GtkWidget *treeview_chats;
- GtkWidget *scrolledwindow_chats;
- EmpathyChatView *chatview_chats;
-
- gchar *last_find;
-
- TplLogManager *log_manager;
-
- /* Those are only used while waiting for the account chooser to be ready */
- TpAccount *selected_account;
- gchar *selected_chat_id;
- gboolean selected_is_chatroom;
+typedef struct
+{
+ GtkWidget *window;
+
+ GtkWidget *button_profile;
+ GtkWidget *button_chat;
+ GtkWidget *button_call;
+ GtkWidget *button_video;
+
+ GtkWidget *search_entry;
+
+ GtkWidget *treeview_who;
+ GtkWidget *treeview_what;
+ GtkWidget *treeview_when;
+ GtkWidget *treeview_events;
+
+ GtkTreeStore *store_events;
+
+ GtkWidget *account_chooser;
+
+ gchar *last_find;
+
+ TplActionChain *chain;
+ TplLogManager *log_manager;
+
+ /* Used to cancel logger calls when no longer needed */
+ guint count;
+
+ /* List of owned TplLogSearchHits, free with tpl_log_search_hit_free */
+ GList *hits;
+ guint source;
+
+ /* Only used while waiting for the account chooser to be ready */
+ TpAccount *selected_account;
+ gchar *selected_chat_id;
+ gboolean selected_is_chatroom;
} EmpathyLogWindow;
-static void log_window_destroy_cb (GtkWidget *widget,
- EmpathyLogWindow *window);
-static void log_window_entry_find_changed_cb (GtkWidget *entry,
- EmpathyLogWindow *window);
-static void log_window_find_changed_cb (GtkTreeSelection *selection,
- EmpathyLogWindow *window);
-static void log_window_find_populate (EmpathyLogWindow *window,
- const gchar *search_criteria);
-static void log_window_find_setup (EmpathyLogWindow *window);
-static void log_window_button_find_clicked_cb (GtkWidget *widget,
- EmpathyLogWindow *window);
-static void log_window_entry_find_activate_cb (GtkWidget *widget,
- EmpathyLogWindow *window);
-static void log_window_button_next_clicked_cb (GtkWidget *widget,
- EmpathyLogWindow *window);
-static void log_window_button_previous_clicked_cb (GtkWidget *widget,
- EmpathyLogWindow *window);
-static void log_window_chats_changed_cb (GtkTreeSelection *selection,
- EmpathyLogWindow *window);
-static void log_window_chats_populate (EmpathyLogWindow *window);
-static void log_window_chats_setup (EmpathyLogWindow *window);
-static void log_window_chats_accounts_changed_cb (GtkWidget *combobox,
- EmpathyLogWindow *window);
-static void log_window_chats_set_selected (EmpathyLogWindow *window);
-static gboolean log_window_chats_get_selected (EmpathyLogWindow *window,
- TpAccount **account,
- TplEntity **target);
-static void log_window_chats_get_messages (EmpathyLogWindow *window,
- GDate *date_to_show);
-static void log_window_calendar_chats_day_selected_cb (GtkWidget *calendar,
- EmpathyLogWindow *window);
-static void log_window_calendar_chats_month_changed_cb (GtkWidget *calendar,
- EmpathyLogWindow *window);
-static void log_window_entry_chats_changed_cb (GtkWidget *entry,
- EmpathyLogWindow *window);
-static void log_window_entry_chats_activate_cb (GtkWidget *entry,
- EmpathyLogWindow *window);
-static void log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
- EmpathyLogWindow *window);
+static void log_window_destroy_cb (GtkWidget *widget,
+ EmpathyLogWindow *window);
+static void log_window_search_entry_changed_cb (GtkWidget *entry,
+ EmpathyLogWindow *window);
+static void log_window_search_entry_activate_cb (GtkWidget *widget,
+ EmpathyLogWindow *window);
+static void log_window_search_entry_icon_pressed_cb (GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkEvent *event,
+ gpointer user_data);
+static void log_window_who_populate (EmpathyLogWindow *window);
+static void log_window_who_setup (EmpathyLogWindow *window);
+static void log_window_when_setup (EmpathyLogWindow *window);
+static void log_window_what_setup (EmpathyLogWindow *window);
+static void log_window_events_setup (EmpathyLogWindow *window);
+static void log_window_chats_accounts_changed_cb (GtkWidget *combobox,
+ EmpathyLogWindow *window);
+static void log_window_chats_set_selected (EmpathyLogWindow *window);
+static void log_window_chats_get_messages (EmpathyLogWindow *window,
+ gboolean force_get_dates);
+static void log_window_when_changed_cb (GtkTreeSelection *selection,
+ EmpathyLogWindow *window);
+static void log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
+ EmpathyLogWindow *window);
static void
empathy_account_chooser_filter_has_logs (TpAccount *account,
- EmpathyAccountChooserFilterResultCallback callback,
- gpointer callback_data,
- gpointer user_data);
-
-enum {
- COL_FIND_ACCOUNT_ICON,
- COL_FIND_ACCOUNT_NAME,
- COL_FIND_ACCOUNT,
- COL_FIND_CHAT_NAME,
- COL_FIND_TARGET,
- COL_FIND_DATE,
- COL_FIND_DATE_READABLE,
- COL_FIND_COUNT
+ EmpathyAccountChooserFilterResultCallback callback,
+ gpointer callback_data,
+ gpointer user_data);
+
+enum
+{
+ COL_TYPE_ANY,
+ COL_TYPE_SEPARATOR,
+ COL_TYPE_NORMAL
};
-enum {
- COL_CHAT_ICON,
- COL_CHAT_NAME,
- COL_CHAT_ACCOUNT,
- COL_CHAT_TARGET,
- COL_CHAT_COUNT
+enum
+{
+ COL_WHO_TYPE,
+ COL_WHO_ICON,
+ COL_WHO_NAME,
+ COL_WHO_ACCOUNT,
+ COL_WHO_TARGET,
+ COL_WHO_COUNT
};
-static EmpathyLogWindow *log_window = NULL;
+enum
+{
+ COL_WHAT_TYPE,
+ COL_WHAT_SUBTYPE,
+ COL_WHAT_TEXT,
+ COL_WHAT_ICON,
+ COL_WHAT_EXPANDER,
+ COL_WHAT_COUNT
+};
-static void
-account_manager_prepared_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+enum
+{
+ COL_WHEN_DATE,
+ COL_WHEN_TEXT,
+ COL_WHEN_ICON,
+ COL_WHEN_COUNT
+};
+
+enum
+{
+ COL_EVENTS_TYPE,
+ COL_EVENTS_TS,
+ COL_EVENTS_PRETTY_DATE,
+ COL_EVENTS_ICON,
+ COL_EVENTS_TEXT,
+ COL_EVENTS_ACCOUNT,
+ COL_EVENTS_TARGET,
+ COL_EVENTS_EVENT,
+ COL_EVENTS_COUNT
+};
+
+#define CALENDAR_ICON "stock_calendar"
+
+/* Seconds between two messages to be considered one conversation */
+#define MAX_GAP 30*60
+
+#define WHAT_TYPE_SEPARATOR -1
+
+typedef enum
{
- TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
- EmpathyLogWindow *window = user_data;
- guint account_num;
- GList *accounts;
- GError *error = NULL;
+ EVENT_CALL_INCOMING = 1 << 0,
+ EVENT_CALL_OUTGOING = 1 << 1,
+ EVENT_CALL_MISSED = 1 << 2,
+ EVENT_CALL_ALL = 1 << 3,
+} EventSubtype;
- if (log_window == NULL)
- return;
+static EmpathyLogWindow *log_window = NULL;
- if (!tp_account_manager_prepare_finish (account_manager, result, &error)) {
- DEBUG ("Failed to prepare account manager: %s", error->message);
- g_error_free (error);
- return;
- }
+static gboolean has_element;
- accounts = tp_account_manager_get_valid_accounts (account_manager);
- account_num = g_list_length (accounts);
- g_list_free (accounts);
+#ifndef _date_copy
+#define _date_copy(d) g_date_new_julian (g_date_get_julian (d))
+#endif
- gtk_widget_show_all (window->hbox_chats);
+typedef struct
+{
+ EmpathyLogWindow *window;
+ TpAccount *account;
+ TplEntity *entity;
+ GDate *date;
+ TplEventTypeMask event_mask;
+ EventSubtype subtype;
+ guint count;
+} Ctx;
+
+static Ctx *
+ctx_new (EmpathyLogWindow *window,
+ TpAccount *account,
+ TplEntity *entity,
+ GDate *date,
+ TplEventTypeMask event_mask,
+ EventSubtype subtype,
+ guint count)
+{
+ Ctx *ctx = g_slice_new0 (Ctx);
+
+ ctx->window = window;
+ if (account != NULL)
+ ctx->account = g_object_ref (account);
+ if (entity != NULL)
+ ctx->entity = g_object_ref (entity);
+ if (date != NULL)
+ ctx->date = _date_copy (date);
+ ctx->event_mask = event_mask;
+ ctx->subtype = subtype;
+ ctx->count = count;
+
+ return ctx;
}
static void
-account_chooser_ready_cb (EmpathyAccountChooser *chooser,
- EmpathyLogWindow *window)
+ctx_free (Ctx *ctx)
{
- gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1);
+ tp_clear_object (&ctx->account);
+ tp_clear_object (&ctx->entity);
+ tp_clear_pointer (&ctx->date, g_date_free);
- /* We'll display the account once the model has been populate with the chats
- * of this account. */
- empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (
- window->account_chooser_chats), window->selected_account);
+ g_slice_free (Ctx, ctx);
+}
+
+static void
+account_chooser_ready_cb (EmpathyAccountChooser *chooser,
+ EmpathyLogWindow *window)
+{
+ /* We'll display the account once the model has been populate with the chats
+ * of this account. */
+ empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (
+ window->account_chooser), window->selected_account);
}
static void
select_account_once_ready (EmpathyLogWindow *self,
- TpAccount *account,
- const gchar *chat_id,
- gboolean is_chatroom)
+ TpAccount *account,
+ const gchar *chat_id,
+ gboolean is_chatroom)
{
- EmpathyAccountChooser *account_chooser = EMPATHY_ACCOUNT_CHOOSER (self->account_chooser_chats);
+ EmpathyAccountChooser *account_chooser;
- tp_clear_object (&self->selected_account);
- self->selected_account = g_object_ref (account);
+ account_chooser = EMPATHY_ACCOUNT_CHOOSER (self->account_chooser);
- g_free (self->selected_chat_id);
- self->selected_chat_id = g_strdup (chat_id);
+ tp_clear_object (&self->selected_account);
+ self->selected_account = g_object_ref (account);
- self->selected_is_chatroom = is_chatroom;
+ g_free (self->selected_chat_id);
+ self->selected_chat_id = g_strdup (chat_id);
- if (empathy_account_chooser_is_ready (account_chooser))
- account_chooser_ready_cb (account_chooser, self);
- else
- /* Chat will be selected once the account chooser is ready */
- g_signal_connect (account_chooser, "ready",
- G_CALLBACK (account_chooser_ready_cb), self);
-}
+ self->selected_is_chatroom = is_chatroom;
-GtkWidget *
-empathy_log_window_show (TpAccount *account,
- const gchar *chat_id,
- gboolean is_chatroom,
- GtkWindow *parent)
-{
- EmpathyAccountChooser *account_chooser;
- TpAccountManager *account_manager;
- GtkBuilder *gui;
- gchar *filename;
- EmpathyLogWindow *window;
- EmpathyThemeManager *theme_mgr;
- GtkWidget *menu_delete;
-
- if (log_window != NULL) {
- gtk_window_present (GTK_WINDOW (log_window->window));
-
- if (account != NULL && chat_id != NULL) {
- gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook), 1);
- select_account_once_ready (log_window, account, chat_id, is_chatroom);
- }
-
- return log_window->window;
- }
-
- log_window = g_new0 (EmpathyLogWindow, 1);
- log_window->log_manager = tpl_log_manager_dup_singleton ();
-
- window = log_window;
-
- filename = empathy_file_lookup ("empathy-log-window.ui",
- "libempathy-gtk");
- gui = empathy_builder_get_file (filename,
- "log_window", &window->window,
- "menu_delete", &menu_delete,
- "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,
- "hbox_chats", &window->hbox_chats,
- "treeview_chats", &window->treeview_chats,
- "scrolledwindow_chats", &window->scrolledwindow_chats,
- NULL);
- g_free (filename);
-
- empathy_builder_connect (gui, window,
- "log_window", "destroy", log_window_destroy_cb,
- "entry_find", "changed", log_window_entry_find_changed_cb,
- "entry_find", "activate", log_window_entry_find_activate_cb,
- "button_previous", "clicked", log_window_button_previous_clicked_cb,
- "button_next", "clicked", log_window_button_next_clicked_cb,
- "button_find", "clicked", log_window_button_find_clicked_cb,
- "entry_chats", "changed", log_window_entry_chats_changed_cb,
- "entry_chats", "activate", log_window_entry_chats_activate_cb,
- "menu_delete", "activate", log_window_delete_menu_clicked_cb,
- NULL);
-
- g_object_unref (gui);
-
- g_object_add_weak_pointer (G_OBJECT (window->window),
- (gpointer) &log_window);
-
- /* We set this up here so we can block it when needed. */
- g_signal_connect (window->calendar_chats, "day-selected",
- G_CALLBACK (log_window_calendar_chats_day_selected_cb),
- window);
- g_signal_connect (window->calendar_chats, "month-changed",
- G_CALLBACK (log_window_calendar_chats_month_changed_cb),
- window);
-
- /* Configure Search EmpathyChatView */
- theme_mgr = empathy_theme_manager_dup_singleton ();
- window->chatview_find = empathy_theme_manager_create_view (theme_mgr);
- gtk_container_add (GTK_CONTAINER (window->scrolledwindow_find),
- GTK_WIDGET (window->chatview_find));
- gtk_widget_show (GTK_WIDGET (window->chatview_find));
-
- /* Configure Contacts EmpathyChatView */
- window->chatview_chats = empathy_theme_manager_create_view (theme_mgr);
- gtk_container_add (GTK_CONTAINER (window->scrolledwindow_chats),
- GTK_WIDGET (window->chatview_chats));
- gtk_widget_show (GTK_WIDGET (window->chatview_chats));
- g_object_unref (theme_mgr);
-
- /* Account chooser for chats */
- window->account_chooser_chats = empathy_account_chooser_new ();
- account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats);
- empathy_account_chooser_set_filter (account_chooser, empathy_account_chooser_filter_has_logs, NULL);
-
- gtk_box_pack_start (GTK_BOX (window->hbox_chats),
- window->account_chooser_chats,
- FALSE, TRUE, 0);
-
- g_signal_connect (window->account_chooser_chats, "changed",
- G_CALLBACK (log_window_chats_accounts_changed_cb),
- window);
-
- /* Populate */
- account_manager = tp_account_manager_dup ();
- tp_account_manager_prepare_async (account_manager, NULL,
- account_manager_prepared_cb, window);
- g_object_unref (account_manager);
-
- /* Search List */
- log_window_find_setup (window);
-
- /* Contacts */
- log_window_chats_setup (window);
- log_window_chats_populate (window);
-
- if (account != NULL && chat_id != NULL)
- select_account_once_ready (window, account, chat_id, is_chatroom);
-
- if (parent != NULL) {
- gtk_window_set_transient_for (GTK_WINDOW (window->window),
- GTK_WINDOW (parent));
- }
-
- gtk_widget_show (window->window);
-
- return window->window;
+ if (empathy_account_chooser_is_ready (account_chooser))
+ account_chooser_ready_cb (account_chooser, self);
+ else
+ /* Chat will be selected once the account chooser is ready */
+ g_signal_connect (account_chooser, "ready",
+ G_CALLBACK (account_chooser_ready_cb), self);
}
static void
-log_window_destroy_cb (GtkWidget *widget,
- EmpathyLogWindow *window)
+toolbutton_profile_clicked (GtkToolButton *toolbutton,
+ EmpathyLogWindow *window)
{
- g_free (window->last_find);
- g_object_unref (window->log_manager);
- tp_clear_object (&window->selected_account);
- g_free (window->selected_chat_id);
+ GtkTreeView *view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GList *paths;
+ TpAccount *account;
+ TplEntity *target;
+ EmpathyContact *contact;
+ gint type;
+
+ g_return_if_fail (window != NULL);
+
+ view = GTK_TREE_VIEW (log_window->treeview_who);
+ selection = gtk_tree_view_get_selection (view);
+
+ paths = gtk_tree_selection_get_selected_rows (selection, &model);
+ g_return_if_fail (paths != NULL);
- g_free (window);
+ path = paths->data;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COL_WHO_ACCOUNT, &account,
+ COL_WHO_TARGET, &target,
+ COL_WHO_TYPE, &type,
+ -1);
+
+ g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
+
+ g_return_if_fail (type == COL_TYPE_NORMAL);
+
+ contact = empathy_contact_from_tpl_contact (account, target);
+ empathy_contact_information_dialog_show (contact,
+ GTK_WINDOW (window->window));
+ g_object_unref (contact);
+
+ g_object_unref (account);
+ g_object_unref (target);
}
-/*
- * Search code.
- */
static void
-log_window_entry_find_changed_cb (GtkWidget *entry,
- EmpathyLogWindow *window)
+toolbutton_chat_clicked (GtkToolButton *toolbutton,
+ EmpathyLogWindow *window)
{
- const gchar *str;
- gboolean is_sensitive = TRUE;
+ GtkTreeView *view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GList *paths;
+ TpAccount *account;
+ TplEntity *target;
+ EmpathyContact *contact;
+ gint type;
+
+ g_return_if_fail (window != NULL);
+
+ view = GTK_TREE_VIEW (log_window->treeview_who);
+ selection = gtk_tree_view_get_selection (view);
- str = gtk_entry_get_text (GTK_ENTRY (window->entry_find));
+ paths = gtk_tree_selection_get_selected_rows (selection, &model);
+ g_return_if_fail (paths != NULL);
- is_sensitive &= !EMP_STR_EMPTY (str);
- is_sensitive &=
- !window->last_find ||
- (window->last_find && tp_strdiff (window->last_find, str));
+ path = paths->data;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COL_WHO_ACCOUNT, &account,
+ COL_WHO_TARGET, &target,
+ COL_WHO_TYPE, &type,
+ -1);
- gtk_widget_set_sensitive (window->button_find, is_sensitive);
+ g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
+
+ g_return_if_fail (type == COL_TYPE_NORMAL);
+
+ contact = empathy_contact_from_tpl_contact (account, target);
+ empathy_dispatcher_chat_with_contact (contact,
+ gtk_get_current_event_time ());
+
+ g_object_unref (contact);
+ g_object_unref (account);
+ g_object_unref (target);
}
static void
-got_events_for_date_cb (GObject *manager,
- GAsyncResult *result,
- gpointer user_data)
-{
- EmpathyLogWindow *window = user_data;
- GList *messages;
- GList *l;
- gboolean can_do_previous;
- gboolean can_do_next;
- GError *error = NULL;
-
- if (log_window == NULL)
- return;
-
- if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (manager),
- result, &messages, &error)) {
- DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting",
- error->message);
- empathy_chat_view_append_event (window->chatview_find,
- "Unable to retrieve messages for the selected date");
- g_error_free (error);
- return;
- }
-
- for (l = messages; l; l = l->next) {
- EmpathyMessage *message;
-
- g_assert (TPL_IS_EVENT (l->data));
-
- message = empathy_message_from_tpl_log_event (l->data);
- g_object_unref (l->data);
- empathy_chat_view_append_message (window->chatview_find, message);
- g_object_unref (message);
- }
- g_list_free (messages);
-
- /* Scroll to the most recent messages */
- empathy_chat_view_scroll (window->chatview_find, TRUE);
-
- /* Highlight and find messages */
- empathy_chat_view_highlight (window->chatview_find,
- window->last_find,
- FALSE);
- empathy_chat_view_find_next (window->chatview_find,
- window->last_find,
- TRUE,
- FALSE);
- empathy_chat_view_find_abilities (window->chatview_find,
- window->last_find,
- FALSE,
- &can_do_previous,
- &can_do_next);
- gtk_widget_set_sensitive (window->button_previous, can_do_previous);
- gtk_widget_set_sensitive (window->button_next, can_do_next);
- gtk_widget_set_sensitive (window->button_find, FALSE);
-}
-
-static GDate *
-gdate_from_str (const gchar *str)
-{
- guint u;
- guint day, month, year;
-
- if (sscanf (str, "%u", &u) != 1)
- return NULL;
-
- day = (u % 100);
- month = ((u / 100) % 100);
- year = (u / 10000);
-
- if (!g_date_valid_dmy (day, month, year))
- return NULL;
-
- return g_date_new_dmy (day, month, year);
+toolbutton_av_clicked (GtkToolButton *toolbutton,
+ EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GList *paths;
+ TpAccount *account;
+ gchar *contact;
+ gint type;
+ gboolean video;
+
+ g_return_if_fail (window != NULL);
+
+ view = GTK_TREE_VIEW (log_window->treeview_who);
+ selection = gtk_tree_view_get_selection (view);
+
+ paths = gtk_tree_selection_get_selected_rows (selection, &model);
+ g_return_if_fail (paths != NULL);
+
+ path = paths->data;
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COL_WHO_ACCOUNT, &account,
+ COL_WHO_NAME, &contact,
+ COL_WHO_TYPE, &type,
+ -1);
+
+ g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
+
+ g_return_if_fail (type == COL_TYPE_NORMAL);
+
+ video = (GTK_WIDGET (toolbutton) == window->button_video);
+
+ empathy_call_new_with_streams (contact, account,
+ TRUE, video, gtk_get_current_event_time ());
+
+ g_free (contact);
+ g_object_unref (account);
}
-static void
-log_window_find_changed_cb (GtkTreeSelection *selection,
- EmpathyLogWindow *window)
+GtkWidget *
+empathy_log_window_show (TpAccount *account,
+ const gchar *chat_id,
+ gboolean is_chatroom,
+ GtkWindow *parent)
{
- GtkTreeView *view;
- GtkTreeModel *model;
- GtkTreeIter iter;
- TpAccount *account;
- TplEntity *target;
- gchar *date;
- GDate *gdate;
+ EmpathyAccountChooser *account_chooser;
+ GtkBuilder *gui;
+ gchar *filename;
+ EmpathyLogWindow *window;
+ GtkWidget *vbox, *accounts, *search, *label, *quit;
+
+ if (log_window != NULL)
+ {
+ gtk_window_present (GTK_WINDOW (log_window->window));
+
+ if (account != NULL && chat_id != NULL)
+ select_account_once_ready (log_window, account, chat_id, is_chatroom);
+
+ return log_window->window;
+ }
+
+ log_window = g_new0 (EmpathyLogWindow, 1);
+ log_window->chain = _tpl_action_chain_new_async (NULL, NULL, NULL);
+
+ log_window->log_manager = tpl_log_manager_dup_singleton ();
+
+ window = log_window;
+
+ filename = empathy_file_lookup ("empathy-log-window.ui", "libempathy-gtk");
+ gui = empathy_builder_get_file (filename,
+ "log_window", &window->window,
+ "toolbutton_profile", &window->button_profile,
+ "toolbutton_chat", &window->button_chat,
+ "toolbutton_call", &window->button_call,
+ "toolbutton_video", &window->button_video,
+ "toolbutton_accounts", &accounts,
+ "toolbutton_search", &search,
+ "imagemenuitem_quit", &quit,
+ "treeview_who", &window->treeview_who,
+ "treeview_what", &window->treeview_what,
+ "treeview_when", &window->treeview_when,
+ "treeview_events", &window->treeview_events,
+ NULL);
+ g_free (filename);
+
+ empathy_builder_connect (gui, window,
+ "log_window", "destroy", log_window_destroy_cb,
+ "toolbutton_profile", "clicked", toolbutton_profile_clicked,
+ "toolbutton_chat", "clicked", toolbutton_chat_clicked,
+ "toolbutton_call", "clicked", toolbutton_av_clicked,
+ "toolbutton_video", "clicked", toolbutton_av_clicked,
+ "imagemenuitem_delete", "activate", log_window_delete_menu_clicked_cb,
+ NULL);
+
+ g_object_unref (gui);
+
+ g_object_add_weak_pointer (G_OBJECT (window->window),
+ (gpointer) &log_window);
+
+ g_signal_connect_swapped (quit, "activate",
+ G_CALLBACK (gtk_widget_destroy), window->window);
+
+ /* Account chooser for chats */
+ vbox = gtk_vbox_new (FALSE, 3);
+
+ window->account_chooser = empathy_account_chooser_new ();
+ account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
+ empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
+ empathy_account_chooser_set_filter (account_chooser,
+ empathy_account_chooser_filter_has_logs, NULL);
+
+ g_signal_connect (window->account_chooser, "changed",
+ G_CALLBACK (log_window_chats_accounts_changed_cb),
+ window);
+
+ label = gtk_label_new (_("Show"));
- /* Get selected information */
- view = GTK_TREE_VIEW (window->treeview_find);
- model = gtk_tree_view_get_model (view);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ window->account_chooser,
+ FALSE, FALSE, 0);
- 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);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ label,
+ FALSE, FALSE, 0);
- empathy_chat_view_clear (window->chatview_find);
+ gtk_widget_show_all (vbox);
+ gtk_container_add (GTK_CONTAINER (accounts), vbox);
- return;
- }
+ /* Search entry */
+ vbox = gtk_vbox_new (FALSE, 3);
- gtk_widget_set_sensitive (window->button_previous, TRUE);
- gtk_widget_set_sensitive (window->button_next, TRUE);
+ window->search_entry = gtk_entry_new ();
+ gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
+ GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_FIND);
+ gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
+ GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
- gtk_tree_model_get (model, &iter,
- COL_FIND_ACCOUNT, &account,
- COL_FIND_TARGET, &target,
- COL_FIND_DATE, &date,
- -1);
+ label = gtk_label_new (_("Search"));
- /* Clear all current messages shown in the textview */
- empathy_chat_view_clear (window->chatview_find);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ window->search_entry,
+ FALSE, FALSE, 0);
- /* Turn off scrolling temporarily */
- empathy_chat_view_scroll (window->chatview_find, FALSE);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ label,
+ FALSE, FALSE, 0);
- /* Get messages */
- gdate = gdate_from_str (date);
+ gtk_widget_show_all (vbox);
+ gtk_container_add (GTK_CONTAINER (search), vbox);
- if (gdate != NULL) {
- tpl_log_manager_get_events_for_date_async (window->log_manager,
- account,
- target,
- TPL_EVENT_MASK_TEXT,
- gdate,
- got_events_for_date_cb,
- window);
+ g_signal_connect (window->search_entry, "changed",
+ G_CALLBACK (log_window_search_entry_changed_cb),
+ window);
- g_date_free (gdate);
- }
+ g_signal_connect (window->search_entry, "activate",
+ G_CALLBACK (log_window_search_entry_activate_cb),
+ window);
- g_object_unref (account);
- g_object_unref (target);
- g_free (date);
-}
+ g_signal_connect (window->search_entry, "icon-press",
+ G_CALLBACK (log_window_search_entry_icon_pressed_cb),
+ window);
+ /* Contacts */
+ log_window_events_setup (window);
+ log_window_who_setup (window);
+ log_window_what_setup (window);
+ log_window_when_setup (window);
-static void
-log_manager_searched_new_cb (GObject *manager,
- GAsyncResult *result,
- gpointer user_data)
-{
- GList *hits;
- GList *l;
- GtkTreeIter iter;
- GtkListStore *store = user_data;
- GError *error = NULL;
-
- if (log_window == NULL)
- return;
-
- if (!tpl_log_manager_search_finish (TPL_LOG_MANAGER (manager), result,
- &hits, &error)) {
- DEBUG ("%s. Aborting", error->message);
- g_error_free (error);
- return;
- }
-
- for (l = hits; l; l = l->next) {
- TplLogSearchHit *hit;
- const gchar *account_name;
- const gchar *account_icon;
- gchar date_readable[255];
- gchar tmp[255];
-
- hit = l->data;
-
- /* Protect against invalid data (corrupt or old log files. */
- if (hit->account == NULL || hit->target == NULL) {
- continue;
- }
-
- g_date_strftime (date_readable, sizeof (date_readable),
- EMPATHY_DATE_FORMAT_DISPLAY_SHORT, hit->date);
-
- g_date_strftime (tmp, sizeof (tmp),
- "%Y%m%d", hit->date);
-
- account_name = tp_account_get_display_name (hit->account);
- account_icon = tp_account_get_icon_name (hit->account);
-
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter,
- COL_FIND_ACCOUNT_ICON, account_icon,
- COL_FIND_ACCOUNT_NAME, account_name,
- COL_FIND_ACCOUNT, hit->account,
- COL_FIND_CHAT_NAME, tpl_entity_get_alias (hit->target),
- COL_FIND_TARGET, hit->target,
- COL_FIND_DATE, tmp,
- COL_FIND_DATE_READABLE, date_readable,
- -1);
-
- /* FIXME: Update COL_FIND_CHAT_NAME */
- if (tpl_entity_get_entity_type (hit->target) == TPL_ENTITY_ROOM) {
- } else {
- }
- }
-
- if (hits != NULL) {
- tpl_log_manager_search_free (hits);
- }
+ log_window_who_populate (window);
+
+ if (account != NULL && chat_id != NULL)
+ select_account_once_ready (window, account, chat_id, is_chatroom);
+
+ if (parent != NULL)
+ gtk_window_set_transient_for (GTK_WINDOW (window->window),
+ GTK_WINDOW (parent));
+
+ gtk_widget_show (window->window);
+
+ return window->window;
}
static void
-log_window_find_populate (EmpathyLogWindow *window,
- const gchar *search_criteria)
+log_window_destroy_cb (GtkWidget *widget,
+ EmpathyLogWindow *window)
{
- GtkTreeView *view;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkListStore *store;
+ if (window->source != 0)
+ g_source_remove (window->source);
- 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);
+ g_free (window->last_find);
+ _tpl_action_chain_free (window->chain);
+ g_object_unref (window->log_manager);
+ tp_clear_object (&window->selected_account);
+ g_free (window->selected_chat_id);
- empathy_chat_view_clear (window->chatview_find);
+ g_free (window);
+}
- gtk_list_store_clear (store);
+static gboolean
+account_equal (TpAccount *a,
+ TpAccount *b)
+{
+ return g_str_equal (tp_proxy_get_object_path (a),
+ tp_proxy_get_object_path (b));
+}
- if (EMP_STR_EMPTY (search_criteria)) {
- /* Just clear the search. */
- return;
- }
+static gboolean
+entity_equal (TplEntity *a,
+ TplEntity *b)
+{
+ return g_str_equal (tpl_entity_get_identifier (a),
+ tpl_entity_get_identifier (b));
+}
- tpl_log_manager_search_async (window->log_manager,
- search_criteria, TPL_EVENT_MASK_TEXT,
- log_manager_searched_new_cb, (gpointer) store);
+static gboolean
+is_same_confroom (TplEvent *e1,
+ TplEvent *e2)
+{
+ TplEntity *sender1 = tpl_event_get_sender (e1);
+ TplEntity *receiver1 = tpl_event_get_receiver (e1);
+ TplEntity *sender2 = tpl_event_get_sender (e2);
+ TplEntity *receiver2 = tpl_event_get_receiver (e2);
+ TplEntity *room1, *room2;
+
+ if (tpl_entity_get_entity_type (sender1) == TPL_ENTITY_ROOM)
+ room1 = sender1;
+ else if (tpl_entity_get_entity_type (receiver1) == TPL_ENTITY_ROOM)
+ room1 = receiver1;
+ else
+ return FALSE;
+
+ if (tpl_entity_get_entity_type (sender2) == TPL_ENTITY_ROOM)
+ room2 = sender2;
+ else if (tpl_entity_get_entity_type (receiver2) == TPL_ENTITY_ROOM)
+ room2 = receiver2;
+ else
+ return FALSE;
+
+ return g_str_equal (tpl_entity_get_identifier (room1),
+ tpl_entity_get_identifier (room1));
}
-static void
-log_window_find_setup (EmpathyLogWindow *window)
-{
- GtkTreeView *view;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkTreeSortable *sortable;
- GtkTreeViewColumn *column;
- GtkListStore *store;
- GtkCellRenderer *cell;
- gint offset;
-
- view = GTK_TREE_VIEW (window->treeview_find);
- selection = gtk_tree_view_get_selection (view);
-
- /* New store */
- store = gtk_list_store_new (COL_FIND_COUNT,
- G_TYPE_STRING, /* account icon name */
- G_TYPE_STRING, /* account name */
- TP_TYPE_ACCOUNT, /* account */
- G_TYPE_STRING, /* chat name */
- TPL_TYPE_ENTITY, /* target */
- 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 TplEntity *
+event_get_target (TplEvent *event)
+{
+ TplEntity *sender = tpl_event_get_sender (event);
+ TplEntity *receiver = tpl_event_get_receiver (event);
+
+ if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
+ return receiver;
+
+ return sender;
}
-static void
-start_find_search (EmpathyLogWindow *window)
+static gboolean
+model_is_parent (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ TplEvent *event)
{
- const gchar *str;
+ TplEvent *stored_event;
+ TplEntity *target;
+ TpAccount *account;
+ gboolean found = FALSE;
+ GtkTreeIter parent;
+
+ if (gtk_tree_model_iter_parent (model, &parent, iter))
+ return FALSE;
+
+ gtk_tree_model_get (model, iter,
+ COL_EVENTS_ACCOUNT, &account,
+ COL_EVENTS_TARGET, &target,
+ COL_EVENTS_EVENT, &stored_event,
+ -1);
+
+ if (G_OBJECT_TYPE (event) == G_OBJECT_TYPE (stored_event) &&
+ account_equal (account, tpl_event_get_account (event)) &&
+ (entity_equal (target, event_get_target (event)) ||
+ is_same_confroom (event, stored_event)))
+ {
+ GtkTreeIter child;
+ gint64 timestamp;
+
+ gtk_tree_model_iter_nth_child (model, &child, iter,
+ gtk_tree_model_iter_n_children (model, iter) - 1);
+
+ gtk_tree_model_get (model, &child,
+ COL_EVENTS_TS, &timestamp,
+ -1);
+
+ if (ABS (tpl_event_get_timestamp (event) - timestamp) < MAX_GAP)
+ {
+ /* The gap is smaller than 30 min */
+ found = TRUE;
+ }
+ }
+
+ g_object_unref (stored_event);
+ g_object_unref (account);
+ g_object_unref (target);
- str = gtk_entry_get_text (GTK_ENTRY (window->entry_find));
+ return found;
+}
+
+static const gchar *
+get_contact_alias_for_message (EmpathyMessage *message)
+{
+ EmpathyContact *sender, *receiver;
- /* Don't find the same crap again */
- if (window->last_find && !tp_strdiff (window->last_find, str)) {
- return;
- }
+ sender = empathy_message_get_sender (message);
+ receiver = empathy_message_get_receiver (message);
- g_free (window->last_find);
- window->last_find = g_strdup (str);
+ if (empathy_contact_is_user (sender))
+ return empathy_contact_get_alias (receiver);
- log_window_find_populate (window, str);
+ return empathy_contact_get_alias (sender);
}
static void
-log_window_button_find_clicked_cb (GtkWidget *widget,
- EmpathyLogWindow *window)
+get_parent_iter_for_message (TplEvent *event,
+ EmpathyMessage *message,
+ GtkTreeIter *parent)
{
- start_find_search (window);
+ GtkTreeStore *store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean parent_found = FALSE;
+ gboolean next;
+
+ store = log_window->store_events;
+ model = GTK_TREE_MODEL (store);
+
+ for (next = gtk_tree_model_get_iter_first (model, &iter);
+ next;
+ next = gtk_tree_model_iter_next (model, &iter))
+ {
+ if ((parent_found = model_is_parent (model, &iter, event)))
+ break;
+ }
+
+ if (parent_found)
+ {
+ *parent = iter;
+ }
+ else
+ {
+ GDateTime *date;
+ gchar *body, *pretty_date;
+
+ date = g_date_time_new_from_unix_utc (
+ tpl_event_get_timestamp (event));
+
+ pretty_date = g_date_time_format (date,
+ C_("A date with the time", "%A, %e %B %Y %X"));
+
+ body = g_strdup_printf (_("Chat with %s"),
+ get_contact_alias_for_message (message));
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ COL_EVENTS_TS, tpl_event_get_timestamp (event),
+ COL_EVENTS_PRETTY_DATE, pretty_date,
+ COL_EVENTS_TEXT, body,
+ COL_EVENTS_ICON, "stock_text_justify",
+ COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
+ COL_EVENTS_TARGET, event_get_target (event),
+ COL_EVENTS_EVENT, event,
+ -1);
+
+ *parent = iter;
+
+ g_free (body);
+ g_free (pretty_date);
+ g_date_time_unref (date);
+ }
}
-static void
-log_window_entry_find_activate_cb (GtkWidget *entry,
- EmpathyLogWindow *self)
+static const gchar *
+get_icon_for_event (TplEvent *event)
{
- start_find_search (self);
+ const gchar *icon = NULL;
+
+ if (TPL_IS_CALL_EVENT (event))
+ {
+ TplCallEvent *call = TPL_CALL_EVENT (event);
+ TplCallEndReason reason = tpl_call_event_get_end_reason (call);
+ TplEntity *sender = tpl_event_get_sender (event);
+ TplEntity *receiver = tpl_event_get_receiver (event);
+
+ if (reason == TPL_CALL_END_REASON_NO_ANSWER)
+ icon = EMPATHY_IMAGE_CALL_MISSED;
+ else if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
+ icon = EMPATHY_IMAGE_CALL_OUTGOING;
+ else if (tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
+ icon = EMPATHY_IMAGE_CALL_INCOMING;
+ }
+
+ return icon;
}
static void
-log_window_button_next_clicked_cb (GtkWidget *widget,
- EmpathyLogWindow *window)
-{
- if (window->last_find) {
- gboolean can_do_previous;
- gboolean can_do_next;
-
- empathy_chat_view_find_next (window->chatview_find,
- window->last_find,
- FALSE,
- FALSE);
- empathy_chat_view_find_abilities (window->chatview_find,
- window->last_find,
- FALSE,
- &can_do_previous,
- &can_do_next);
- gtk_widget_set_sensitive (window->button_previous, can_do_previous);
- gtk_widget_set_sensitive (window->button_next, can_do_next);
- }
+log_window_append_chat_message (TplEvent *event,
+ EmpathyMessage *message)
+{
+ GtkTreeStore *store = log_window->store_events;
+ GtkTreeIter iter, parent;
+ gchar *pretty_date, *body;
+ GDateTime *date;
+
+ date = g_date_time_new_from_unix_utc (
+ tpl_event_get_timestamp (event));
+
+ pretty_date = g_date_time_format (date, "%X");
+
+ get_parent_iter_for_message (event, message, &parent);
+
+ if (tpl_text_event_get_message_type (TPL_TEXT_EVENT (event))
+ == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION)
+ {
+ body = g_strdup_printf ("* %s %s",
+ tpl_entity_get_alias (tpl_event_get_sender (event)),
+ empathy_message_get_body (message));
+ }
+ else
+ {
+ body = g_strdup_printf (
+ C_("First is a contact, second is what was said", "%s: %s"),
+ tpl_entity_get_alias (tpl_event_get_sender (event)),
+ empathy_message_get_body (message));
+ }
+
+ gtk_tree_store_append (store, &iter, &parent);
+ gtk_tree_store_set (store, &iter,
+ COL_EVENTS_TS, tpl_event_get_timestamp (event),
+ COL_EVENTS_PRETTY_DATE, pretty_date,
+ COL_EVENTS_TEXT, body,
+ COL_EVENTS_ICON, get_icon_for_event (event),
+ COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
+ COL_EVENTS_TARGET, event_get_target (event),
+ COL_EVENTS_EVENT, event,
+ -1);
+
+ g_free (body);
+ g_free (pretty_date);
+ g_date_time_unref (date);
}
static void
-log_window_button_previous_clicked_cb (GtkWidget *widget,
- EmpathyLogWindow *window)
-{
- if (window->last_find) {
- gboolean can_do_previous;
- gboolean can_do_next;
-
- empathy_chat_view_find_previous (window->chatview_find,
- window->last_find,
- FALSE,
- FALSE);
- empathy_chat_view_find_abilities (window->chatview_find,
- window->last_find,
- FALSE,
- &can_do_previous,
- &can_do_next);
- gtk_widget_set_sensitive (window->button_previous, can_do_previous);
- gtk_widget_set_sensitive (window->button_next, can_do_next);
- }
+log_window_append_call (TplEvent *event,
+ EmpathyMessage *message)
+{
+ TplCallEvent *call = TPL_CALL_EVENT (event);
+ GtkTreeStore *store = log_window->store_events;
+ GtkTreeIter iter, child;
+ gchar *pretty_date, *body, *duration, *finished;
+ GDateTime *started_date, *finished_date;
+ GTimeSpan span;
+
+ started_date = g_date_time_new_from_unix_utc (
+ tpl_event_get_timestamp (event));
+
+ pretty_date = g_date_time_format (started_date,
+ C_("A date with the time", "%A, %e %B %Y %X"));
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ COL_EVENTS_TS, tpl_event_get_timestamp (event),
+ COL_EVENTS_PRETTY_DATE, pretty_date,
+ COL_EVENTS_TEXT, empathy_message_get_body (message),
+ COL_EVENTS_ICON, get_icon_for_event (event),
+ COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
+ COL_EVENTS_TARGET, event_get_target (event),
+ COL_EVENTS_EVENT, event,
+ -1);
+
+ if (tpl_call_event_get_end_reason (call) != TPL_CALL_END_REASON_NO_ANSWER)
+ {
+ span = tpl_call_event_get_duration (TPL_CALL_EVENT (event));
+ if (span < 60)
+ duration = g_strdup_printf (_("%" G_GINT64_FORMAT " seconds"), span);
+ else
+ duration = g_strdup_printf (_("%" G_GINT64_FORMAT " minutes"),
+ span / 60);
+
+ finished_date = g_date_time_add (started_date, -span);
+ finished = g_date_time_format (finished_date, "%X");
+ g_date_time_unref (finished_date);
+
+ body = g_strdup_printf (_("Call took %s, ended at %s"),
+ duration, finished);
+
+ g_free (duration);
+ g_free (finished);
+
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child,
+ COL_EVENTS_TS, tpl_event_get_timestamp (event),
+ COL_EVENTS_TEXT, body,
+ COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
+ COL_EVENTS_TARGET, event_get_target (event),
+ COL_EVENTS_EVENT, event,
+ -1);
+ }
+
+ g_free (body);
+ g_free (pretty_date);
+ g_date_time_unref (started_date);
}
-/*
- * Chats Code
- */
+static void
+log_window_append_message (TplEvent *event,
+ EmpathyMessage *message)
+{
+ if (TPL_IS_TEXT_EVENT (event))
+ log_window_append_chat_message (event, message);
+ else if (TPL_IS_CALL_EVENT (event))
+ log_window_append_call (event, message);
+ else
+ DEBUG ("Message type not handled");
+}
static void
-log_window_chats_changed_cb (GtkTreeSelection *selection,
- EmpathyLogWindow *window)
+add_all_accounts_and_entities (GList **accounts,
+ GList **entities)
{
- gboolean selected;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ view = GTK_TREE_VIEW (log_window->treeview_who);
+ model = gtk_tree_view_get_model (view);
+
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return;
+
+ do
+ {
+ TpAccount *account;
+ TplEntity *entity;
+ gint type;
+
+ gtk_tree_model_get (model, &iter,
+ COL_WHO_ACCOUNT, &account,
+ COL_WHO_TARGET, &entity,
+ COL_WHO_TYPE, &type,
+ -1);
- /* The calendar has to be sensitive only if there is something selected */
- selected = log_window_chats_get_selected (window, NULL, NULL);
- gtk_widget_set_sensitive (window->calendar_chats, selected);
+ if (type != COL_TYPE_NORMAL)
+ continue;
- /* Use last date by default */
- gtk_calendar_clear_marks (GTK_CALENDAR (window->calendar_chats));
+ if (accounts != NULL)
+ *accounts = g_list_append (*accounts, account);
- log_window_chats_get_messages (window, NULL);
+ if (entities != NULL)
+ *entities = g_list_append (*entities, entity);
+ }
+ while (gtk_tree_model_iter_next (model, &iter));
}
-static void
-log_manager_got_entities_cb (GObject *manager,
- GAsyncResult *result,
- gpointer user_data)
-{
- GList *entities;
- GList *l;
- GtkTreeView *view;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkListStore *store;
- GtkTreeIter iter;
- GError *error = NULL;
- gboolean select_account = FALSE;
- TpAccount *account = user_data;
-
- if (log_window == NULL)
- goto out;
-
- if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
- result, &entities, &error)) {
- DEBUG ("%s. Aborting", error->message);
- g_error_free (error);
- goto out;
- }
-
- view = GTK_TREE_VIEW (log_window->treeview_chats);
- model = gtk_tree_view_get_model (view);
- selection = gtk_tree_view_get_selection (view);
- store = GTK_LIST_STORE (model);
-
- for (l = entities; l; l = l->next) {
- TplEntity *entity;
-
- entity = TPL_ENTITY (l->data);
-
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter,
- COL_CHAT_ICON, "empathy-available", /* FIXME */
- COL_CHAT_NAME, tpl_entity_get_alias (entity),
- COL_CHAT_ACCOUNT, account,
- COL_CHAT_TARGET, entity,
- -1);
-
- if (log_window->selected_account != NULL &&
- !tp_strdiff (tp_proxy_get_object_path (account),
- tp_proxy_get_object_path (log_window->selected_account)))
- select_account = TRUE;
-
- /* FIXME: Update COL_CHAT_ICON/NAME */
- if (tpl_entity_get_entity_type (entity) == TPL_ENTITY_ROOM) {
- } else {
- }
- }
- g_list_free_full (entities, g_object_unref);
-
- /* Unblock signals */
- g_signal_handlers_unblock_by_func (selection,
- log_window_chats_changed_cb,
- log_window);
-
- /* We display the selected account if we populate the model with chats from
- * this account. */
- if (select_account)
- log_window_chats_set_selected (log_window);
+static gboolean
+log_window_get_selected (EmpathyLogWindow *window,
+ GList **accounts,
+ GList **entities,
+ GList **dates,
+ TplEventTypeMask *event_mask,
+ EventSubtype *subtype)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ TplEventTypeMask ev = 0;
+ EventSubtype st = 0;
+ GList *paths, *l;
+ gint type;
+
+ view = GTK_TREE_VIEW (window->treeview_who);
+ model = gtk_tree_view_get_model (view);
+ selection = gtk_tree_view_get_selection (view);
+
+ paths = gtk_tree_selection_get_selected_rows (selection, NULL);
+ if (paths == NULL)
+ return FALSE;
+
+ if (accounts != NULL)
+ *accounts = NULL;
+ if (entities != NULL)
+ *entities = NULL;
+
+ for (l = paths; l != NULL; l = l->next)
+ {
+ GtkTreePath *path = l->data;
+ TpAccount *account;
+ TplEntity *entity;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COL_WHO_ACCOUNT, &account,
+ COL_WHO_TARGET, &entity,
+ COL_WHO_TYPE, &type,
+ -1);
+
+ if (type == COL_TYPE_ANY)
+ {
+ if (accounts != NULL || entities != NULL)
+ add_all_accounts_and_entities (accounts, entities);
+ break;
+ }
+
+ if (accounts != NULL)
+ *accounts = g_list_append (*accounts, g_object_ref (account));
+
+ if (entities != NULL)
+ *entities = g_list_append (*entities, g_object_ref (entity));
+
+ g_object_unref (account);
+ g_object_unref (entity);
+ }
+ g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
+
+ view = GTK_TREE_VIEW (window->treeview_what);
+ model = gtk_tree_view_get_model (view);
+ selection = gtk_tree_view_get_selection (view);
+
+ paths = gtk_tree_selection_get_selected_rows (selection, NULL);
+ for (l = paths; l != NULL; l = l->next)
+ {
+ GtkTreePath *path = l->data;
+ TplEventTypeMask mask;
+ EventSubtype submask;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COL_WHAT_TYPE, &mask,
+ COL_WHAT_SUBTYPE, &submask,
+ -1);
+
+ ev |= mask;
+ st |= submask;
+ }
+ g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
+
+ view = GTK_TREE_VIEW (window->treeview_when);
+ model = gtk_tree_view_get_model (view);
+ selection = gtk_tree_view_get_selection (view);
+
+ if (dates != NULL)
+ {
+ *dates = NULL;
+
+ paths = gtk_tree_selection_get_selected_rows (selection, NULL);
+ for (l = paths; l != NULL; l = l->next)
+ {
+ GtkTreePath *path = l->data;
+ GDate *date;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ COL_WHEN_DATE, &date,
+ -1);
+
+ *dates = g_list_append (*dates, date);
+ }
+ g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
+ }
+
+ if (event_mask != NULL)
+ *event_mask = ev;
+
+ if (subtype != NULL)
+ *subtype = st;
+
+ return TRUE;
+}
-out:
- g_object_unref (account);
+static gboolean
+model_has_entity (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ TplLogSearchHit *hit = data;
+ TplEntity *e;
+ TpAccount *a;
+ gboolean ret = FALSE;
+
+ gtk_tree_model_get (model, iter,
+ COL_WHO_TARGET, &e,
+ COL_WHO_ACCOUNT, &a,
+ -1);
+
+ if (e != NULL && entity_equal (hit->target, e) &&
+ a != NULL && account_equal (hit->account, a))
+ {
+ ret = has_element = TRUE;
+ }
+
+ tp_clear_object (&e);
+ tp_clear_object (&a);
+
+ return ret;
}
+static gboolean
+model_has_date (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GDate *date = data;
+ GDate *d;
+
+ gtk_tree_model_get (model, iter,
+ COL_WHEN_DATE, &d,
+ -1);
+
+ if (!g_date_compare (date, d))
+ {
+ has_element = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+get_events_for_date (TplActionChain *chain, gpointer user_data);
+
static void
-log_window_chats_populate (EmpathyLogWindow *window)
+populate_events_from_search_hits (GList *accounts,
+ GList *targets,
+ GList *dates)
{
- EmpathyAccountChooser *account_chooser;
- TpAccount *account;
+ TplEventTypeMask event_mask;
+ EventSubtype subtype;
+ GDate *anytime;
+ GList *l;
+ gboolean is_anytime = FALSE;
- GtkTreeView *view;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkListStore *store;
+ if (!log_window_get_selected (log_window,
+ NULL, NULL, NULL, &event_mask, &subtype))
+ return;
- account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats);
- account = empathy_account_chooser_dup_account (account_chooser);
+ anytime = g_date_new_dmy (2, 1, -1);
+ if (g_list_find_custom (dates, anytime, (GCompareFunc) g_date_compare))
+ is_anytime = TRUE;
+
+ for (l = log_window->hits; l != NULL; l = l->next)
+ {
+ TplLogSearchHit *hit = l->data;
+ GList *acc, *targ;
+ gboolean found = FALSE;
+
+ /* Protect against invalid data (corrupt or old log files). */
+ if (hit->account == NULL || hit->target == NULL)
+ continue;
+
+ for (acc = accounts, targ = targets;
+ acc != NULL && targ != NULL && !found;
+ acc = acc->next, targ = targ->next)
+ {
+ TpAccount *account = acc->data;
+ TplEntity *target = targ->data;
+
+ if (account_equal (hit->account, account) &&
+ entity_equal (hit->target, target))
+ found = TRUE;
+ }
+
+ if (!found)
+ continue;
- view = GTK_TREE_VIEW (window->treeview_chats);
- model = gtk_tree_view_get_model (view);
- selection = gtk_tree_view_get_selection (view);
- store = GTK_LIST_STORE (model);
+ if (is_anytime ||
+ g_list_find_custom (dates, hit->date, (GCompareFunc) g_date_compare)
+ != NULL)
+ {
+ Ctx *ctx;
- if (account == NULL) {
- gtk_list_store_clear (store);
- return;
- }
+ ctx = ctx_new (log_window, hit->account, hit->target, hit->date,
+ event_mask, subtype, log_window->count);
+ _tpl_action_chain_append (log_window->chain,
+ get_events_for_date, ctx);
+ }
+ }
- /* Block signals to stop the logs being retrieved prematurely */
- g_signal_handlers_block_by_func (selection,
- log_window_chats_changed_cb,
- window);
+ _tpl_action_chain_start (log_window->chain);
- gtk_list_store_clear (store);
+ g_date_free (anytime);
+}
- /* Pass the account reference to the callback */
- tpl_log_manager_get_entities_async (window->log_manager, account,
- log_manager_got_entities_cb, account);
+static gchar *
+format_date_for_display (GDate *date)
+{
+ gchar *text;
+ GDate *now = NULL;
+ gint days_elapsed;
+
+ /* g_date_strftime sucks */
+
+ now = g_date_new ();
+ g_date_set_time_t (now, time (NULL));
+
+ days_elapsed = g_date_days_between (date, now);
+
+ if (days_elapsed < 0)
+ {
+ text = NULL;
+ }
+ else if (days_elapsed == 0)
+ {
+ text = g_strdup (_("Today"));
+ }
+ else if (days_elapsed == 1)
+ {
+ text = g_strdup (_("Yesterday"));
+ }
+ else
+ {
+ GDateTime *dt;
+
+ dt = g_date_time_new_utc (g_date_get_year (date),
+ g_date_get_month (date), g_date_get_day (date),
+ 0, 0, 0);
+
+ if (days_elapsed <= 7)
+ text = g_date_time_format (dt, "%A");
+ else
+ text = g_date_time_format (dt,
+ C_("A date such as '23 May 2010', "
+ "%e is the day, %B the month and %Y the year",
+ "%e %B %Y"));
+
+ g_date_time_unref (dt);
+ }
+
+ g_date_free (now);
+
+ return text;
}
static void
-log_window_chats_setup (EmpathyLogWindow *window)
+populate_dates_from_search_hits (GList *accounts,
+ GList *targets)
{
- GtkTreeView *view;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkTreeSortable *sortable;
- GtkTreeViewColumn *column;
- GtkListStore *store;
- GtkCellRenderer *cell;
+ GList *l;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
- view = GTK_TREE_VIEW (window->treeview_chats);
- selection = gtk_tree_view_get_selection (view);
+ if (log_window == NULL)
+ return;
- /* new store */
- store = gtk_list_store_new (COL_CHAT_COUNT,
- G_TYPE_STRING, /* icon */
- G_TYPE_STRING, /* name */
- TP_TYPE_ACCOUNT, /* account */
- TPL_TYPE_ENTITY); /* target */
+ view = GTK_TREE_VIEW (log_window->treeview_when);
+ model = gtk_tree_view_get_model (view);
+ store = GTK_LIST_STORE (model);
+ selection = gtk_tree_view_get_selection (view);
+
+ for (l = log_window->hits; l != NULL; l = l->next)
+ {
+ TplLogSearchHit *hit = l->data;
+ GList *acc, *targ;
+ gboolean found = FALSE;
+
+ /* Protect against invalid data (corrupt or old log files). */
+ if (hit->account == NULL || hit->target == NULL)
+ continue;
+
+ for (acc = accounts, targ = targets;
+ acc != NULL && targ != NULL && !found;
+ acc = acc->next, targ = targ->next)
+ {
+ TpAccount *account = acc->data;
+ TplEntity *target = targ->data;
+
+ if (account_equal (hit->account, account) &&
+ entity_equal (hit->target, target))
+ found = TRUE;
+ }
+
+ if (!found)
+ continue;
- model = GTK_TREE_MODEL (store);
- sortable = GTK_TREE_SORTABLE (store);
+ /* Add the date if it's not already there */
+ has_element = FALSE;
+ gtk_tree_model_foreach (model, model_has_date, hit->date);
+ if (!has_element)
+ {
+ gchar *text = format_date_for_display (hit->date);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHEN_DATE, hit->date,
+ COL_WHEN_TEXT, text,
+ COL_WHEN_ICON, CALENDAR_ICON,
+ -1);
+ }
+ }
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
+ COL_WHEN_TEXT, "separator",
+ -1);
+
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
+ COL_WHEN_TEXT, _("Anytime"),
+ -1);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+}
- gtk_tree_view_set_model (view, model);
+static void
+populate_entities_from_search_hits (void)
+{
+ EmpathyAccountChooser *account_chooser;
+ TpAccount *account;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkListStore *store;
+ GList *l;
- /* new column */
- column = gtk_tree_view_column_new ();
+ view = GTK_TREE_VIEW (log_window->treeview_who);
+ model = gtk_tree_view_get_model (view);
+ store = GTK_LIST_STORE (model);
+
+ gtk_list_store_clear (store);
+
+ account_chooser = EMPATHY_ACCOUNT_CHOOSER (log_window->account_chooser);
+ account = empathy_account_chooser_get_account (account_chooser);
+
+ for (l = log_window->hits; l; l = l->next)
+ {
+ TplLogSearchHit *hit = l->data;
+
+ /* Protect against invalid data (corrupt or old log files). */
+ if (hit->account == NULL || hit->target == NULL)
+ continue;
+
+ /* Filter based on the selected account */
+ if (account != NULL && !account_equal (account, hit->account))
+ continue;
+
+ /* Add the entity if it's not already there */
+ has_element = FALSE;
+ gtk_tree_model_foreach (model, model_has_entity, hit);
+ if (!has_element)
+ {
+ TplEntityType type = tpl_entity_get_entity_type (hit->target);
+ gboolean room = type == TPL_ENTITY_ROOM;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHO_TYPE, COL_TYPE_NORMAL,
+ COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
+ : EMPATHY_IMAGE_AVATAR_DEFAULT,
+ COL_WHO_NAME, tpl_entity_get_alias (hit->target),
+ COL_WHO_ACCOUNT, hit->account,
+ COL_WHO_TARGET, hit->target,
+ -1);
+ }
+ }
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHO_TYPE, COL_TYPE_SEPARATOR,
+ COL_WHO_NAME, "separator",
+ -1);
+
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHO_TYPE, COL_TYPE_ANY,
+ COL_WHO_NAME, _("Anyone"),
+ -1);
+ }
+
+ /* FIXME: select old entity if still available */
+}
- 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);
+static void
+log_manager_searched_new_cb (GObject *manager,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GList *hits;
+ GtkTreeView *view;
+ GtkTreeSelection *selection;
+ GError *error = NULL;
- 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);
+ if (log_window == NULL)
+ return;
+
+ if (!tpl_log_manager_search_finish (TPL_LOG_MANAGER (manager),
+ result, &hits, &error))
+ {
+ DEBUG ("%s. Aborting", error->message);
+ g_error_free (error);
+ return;
+ }
- gtk_tree_view_append_column (view, column);
+ tp_clear_pointer (&log_window->hits, tpl_log_manager_search_free);
+ log_window->hits = hits;
- /* 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);
+ populate_entities_from_search_hits ();
- /* set up signals */
- g_signal_connect (selection, "changed",
- G_CALLBACK (log_window_chats_changed_cb),
- window);
+ view = GTK_TREE_VIEW (log_window->treeview_when);
+ selection = gtk_tree_view_get_selection (view);
- g_object_unref (store);
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_when_changed_cb,
+ log_window);
}
static void
-log_window_chats_accounts_changed_cb (GtkWidget *combobox,
- EmpathyLogWindow *window)
+log_window_find_populate (EmpathyLogWindow *window,
+ const gchar *search_criteria)
{
- /* Clear all current messages shown in the textview */
- empathy_chat_view_clear (window->chatview_chats);
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
- log_window_chats_populate (window);
+ gtk_tree_store_clear (window->store_events);
- /* No chat is selected as we just changed the account */
- gtk_widget_set_sensitive (window->calendar_chats, FALSE);
-}
+ view = GTK_TREE_VIEW (window->treeview_who);
+ model = gtk_tree_view_get_model (view);
+ store = GTK_LIST_STORE (model);
-static void
-log_window_chats_set_selected (EmpathyLogWindow *window)
-{
- 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)) {
- TpAccount *this_account;
- TplEntity *this_target;
- const gchar *this_chat_id;
- gboolean this_is_chatroom;
-
- gtk_tree_model_get (model, &iter,
- COL_CHAT_ACCOUNT, &this_account,
- COL_CHAT_TARGET, &this_target,
- -1);
-
- this_chat_id = tpl_entity_get_identifier (this_target);
- this_is_chatroom = tpl_entity_get_entity_type (this_target) == TPL_ENTITY_ROOM;
-
- if (this_account == window->selected_account &&
- !tp_strdiff (this_chat_id, window->selected_chat_id) &&
- this_is_chatroom == window->selected_is_chatroom) {
- gtk_tree_selection_select_iter (selection, &iter);
- path = gtk_tree_model_get_path (model, &iter);
- gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
- gtk_tree_path_free (path);
- g_object_unref (this_account);
- g_object_unref (this_target);
- break;
- }
-
- g_object_unref (this_account);
- g_object_unref (this_target);
- }
-
- tp_clear_object (&window->selected_account);
- tp_clear_pointer (&window->selected_chat_id, g_free);
+ gtk_list_store_clear (store);
+
+ view = GTK_TREE_VIEW (window->treeview_when);
+ model = gtk_tree_view_get_model (view);
+ store = GTK_LIST_STORE (model);
+ selection = gtk_tree_view_get_selection (view);
+
+ gtk_list_store_clear (store);
+
+ if (EMP_STR_EMPTY (search_criteria))
+ {
+ tp_clear_pointer (&window->hits, tpl_log_manager_search_free);
+ log_window_who_populate (window);
+ return;
+ }
+
+ g_signal_handlers_block_by_func (selection,
+ log_window_when_changed_cb,
+ window);
+
+ tpl_log_manager_search_async (window->log_manager,
+ search_criteria, TPL_EVENT_MASK_ANY,
+ log_manager_searched_new_cb, NULL);
}
static gboolean
-log_window_chats_get_selected (EmpathyLogWindow *window,
- TpAccount **account,
- TplEntity **target)
+start_find_search (EmpathyLogWindow *window)
{
- GtkTreeView *view;
- GtkTreeModel *model;
- GtkTreeSelection *selection;
- GtkTreeIter iter;
- TplEntity *targ;
- TpAccount *acc = NULL;
+ const gchar *str;
- view = GTK_TREE_VIEW (window->treeview_chats);
- model = gtk_tree_view_get_model (view);
- selection = gtk_tree_view_get_selection (view);
+ str = gtk_entry_get_text (GTK_ENTRY (window->search_entry));
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
- return FALSE;
- }
+ /* Don't find the same crap again */
+ if (window->last_find && !tp_strdiff (window->last_find, str))
+ return FALSE;
- gtk_tree_model_get (model, &iter,
- COL_CHAT_ACCOUNT, &acc,
- COL_CHAT_TARGET, &targ,
- -1);
+ g_free (window->last_find);
+ window->last_find = g_strdup (str);
- if (account != NULL) {
- *account = g_object_ref (acc);
- }
+ log_window_find_populate (window, str);
- if (target != NULL) {
- *target = g_object_ref (targ);
- }
+ return FALSE;
+}
- g_object_unref (acc);
- g_object_unref (targ);
+static void
+log_window_search_entry_changed_cb (GtkWidget *entry,
+ EmpathyLogWindow *window)
+{
+ if (window->source != 0)
+ g_source_remove (window->source);
+ window->source = g_timeout_add (500, (GSourceFunc) start_find_search,
+ window);
+}
- return TRUE;
+static void
+log_window_search_entry_activate_cb (GtkWidget *entry,
+ EmpathyLogWindow *self)
+{
+ start_find_search (self);
}
static void
-log_window_got_messages_for_date_cb (GObject *manager,
+log_window_search_entry_icon_pressed_cb (GtkEntry *entry,
+ GtkEntryIconPosition icon_pos,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
+ return;
+
+ gtk_entry_buffer_set_text (gtk_entry_get_buffer (entry),
+ "", -1);
+}
+
+/*
+ * Chats Code
+ */
+
+static void
+log_window_who_changed_cb (GtkTreeSelection *selection,
+ EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean someone = FALSE;
+
+ DEBUG ("log_window_who_changed_cb");
+
+ view = gtk_tree_selection_get_tree_view (selection);
+ model = gtk_tree_view_get_model (view);
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ /* If 'Anyone' is selected, everything else should be deselected */
+ if (gtk_tree_selection_iter_is_selected (selection, &iter))
+ {
+ g_signal_handlers_block_by_func (selection,
+ log_window_who_changed_cb,
+ window);
+
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_who_changed_cb,
+ window);
+ }
+ else if (gtk_tree_selection_count_selected_rows (selection) == 1)
+ {
+ someone = TRUE;
+ }
+ }
+
+ gtk_widget_set_sensitive (window->button_profile, someone);
+ gtk_widget_set_sensitive (window->button_chat, someone);
+ gtk_widget_set_sensitive (window->button_call, someone);
+ gtk_widget_set_sensitive (window->button_video, someone);
+
+ /* The contact changed, so the dates need to be updated */
+ log_window_chats_get_messages (window, TRUE);
+}
+
+static void
+log_manager_got_entities_cb (GObject *manager,
GAsyncResult *result,
gpointer user_data)
{
- EmpathyLogWindow *window = user_data;
- GList *events;
- GList *l;
- GError *error = NULL;
+ Ctx *ctx = user_data;
+ GList *entities;
+ GList *l;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GError *error = NULL;
+ gboolean select_account = FALSE;
if (log_window == NULL)
- return;
+ goto out;
- if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (manager),
- result, &events, &error)) {
- DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting",
- error->message);
- empathy_chat_view_append_event (window->chatview_find,
- "Unable to retrieve messages for the selected date");
- g_error_free (error);
- return;
- }
-
- for (l = events; l; l = l->next) {
- EmpathyMessage *message = empathy_message_from_tpl_log_event (l->data);
- g_object_unref (l->data);
- empathy_chat_view_append_message (window->chatview_chats,
- message);
- g_object_unref (message);
- }
- g_list_free (events);
+ if (log_window->count != ctx->count)
+ goto out;
- /* Turn back on scrolling */
- empathy_chat_view_scroll (window->chatview_find, TRUE);
+ if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
+ result, &entities, &error))
+ {
+ DEBUG ("%s. Aborting", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ view = GTK_TREE_VIEW (ctx->window->treeview_who);
+ 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_who_changed_cb, ctx->window);
+
+ for (l = entities; l; l = l->next)
+ {
+ TplEntity *entity = TPL_ENTITY (l->data);
+ TplEntityType type = tpl_entity_get_entity_type (entity);
+ gboolean room = type == TPL_ENTITY_ROOM;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHO_TYPE, COL_TYPE_NORMAL,
+ COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
+ : EMPATHY_IMAGE_AVATAR_DEFAULT,
+ COL_WHO_NAME, tpl_entity_get_alias (entity),
+ COL_WHO_ACCOUNT, ctx->account,
+ COL_WHO_TARGET, entity,
+ -1);
+
+ if (ctx->window->selected_account != NULL &&
+ !tp_strdiff (tp_proxy_get_object_path (ctx->account),
+ tp_proxy_get_object_path (ctx->window->selected_account)))
+ select_account = TRUE;
+ }
+ g_list_free_full (entities, g_object_unref);
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ gint type;
+
+ gtk_tree_model_get (model, &iter,
+ COL_WHO_TYPE, &type,
+ -1);
+
+ if (type != COL_TYPE_ANY)
+ {
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHO_TYPE, COL_TYPE_SEPARATOR,
+ COL_WHO_NAME, "separator",
+ -1);
+
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHO_TYPE, COL_TYPE_ANY,
+ COL_WHO_NAME, _("Anyone"),
+ -1);
+ }
+ }
+
+ /* Unblock signals */
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_who_changed_cb,
+ ctx->window);
+
+ /* We display the selected account if we populate the model with chats from
+ * this account. */
+ if (select_account)
+ log_window_chats_set_selected (ctx->window);
- /* Give the search entry main focus */
- gtk_widget_grab_focus (window->entry_chats);
+out:
+ _tpl_action_chain_continue (log_window->chain);
+ ctx_free (ctx);
}
-
static void
-log_window_get_messages_for_date (EmpathyLogWindow *window,
- GDate *date)
+get_entities_for_account (TplActionChain *chain, gpointer user_data)
{
- TpAccount *account;
- TplEntity *target;
+ Ctx *ctx = user_data;
- if (!log_window_chats_get_selected (window, &account, &target)) {
- return;
- }
+ tpl_log_manager_get_entities_async (ctx->window->log_manager, ctx->account,
+ log_manager_got_entities_cb, ctx);
+}
- /* Clear all current messages shown in the textview */
- empathy_chat_view_clear (window->chatview_chats);
+static void
+select_first_entity (TplActionChain *chain, gpointer user_data)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
- /* Turn off scrolling temporarily */
- empathy_chat_view_scroll (window->chatview_find, FALSE);
+ view = GTK_TREE_VIEW (log_window->treeview_who);
+ model = gtk_tree_view_get_model (view);
+ selection = gtk_tree_view_get_selection (view);
- /* Get events */
- tpl_log_manager_get_events_for_date_async (window->log_manager,
- account, target, TPL_EVENT_MASK_TEXT,
- date,
- log_window_got_messages_for_date_cb,
- (gpointer) window);
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ gtk_tree_selection_select_iter (selection, &iter);
- g_object_unref (account);
- g_object_unref (target);
+ _tpl_action_chain_continue (log_window->chain);
}
static void
-log_manager_got_dates_cb (GObject *manager,
- GAsyncResult *result,
- gpointer user_data)
+log_window_who_populate (EmpathyLogWindow *window)
{
- EmpathyLogWindow *window = user_data;
- GList *dates;
- GList *l;
- guint year_selected;
- guint month_selected;
- gboolean day_selected = FALSE;
- GDate *date = NULL;
- GError *error = NULL;
+ EmpathyAccountChooser *account_chooser;
+ TpAccount *account;
+ gboolean all_accounts;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
+ Ctx *ctx;
+
+ if (window->hits != NULL)
+ {
+ populate_entities_from_search_hits ();
+ return;
+ }
- if (log_window == NULL)
- return;
+ account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
+ account = empathy_account_chooser_dup_account (account_chooser);
+ all_accounts = empathy_account_chooser_has_all_selected (account_chooser);
- if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager),
- result, &dates, &error)) {
- DEBUG ("Unable to retrieve messages' dates: %s. Aborting",
- error->message);
- empathy_chat_view_append_event (window->chatview_find,
- "Unable to retrieve messages' dates");
- return;
- }
+ view = GTK_TREE_VIEW (window->treeview_who);
+ model = gtk_tree_view_get_model (view);
+ selection = gtk_tree_view_get_selection (view);
+ store = GTK_LIST_STORE (model);
- for (l = dates; l; l = l->next) {
- GDate *d = l->data;
+ /* Block signals to stop the logs being retrieved prematurely */
+ g_signal_handlers_block_by_func (selection,
+ log_window_who_changed_cb,
+ window);
- gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
- &year_selected,
- &month_selected,
- NULL);
+ gtk_list_store_clear (store);
- month_selected++;
+ /* Unblock signals */
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_who_changed_cb,
+ window);
- if (!l->next) {
- date = d;
- }
+ _tpl_action_chain_clear (window->chain);
+ window->count++;
- if (g_date_get_year (d) != year_selected ||
- g_date_get_month (d) != month_selected) {
- continue;
- }
+ if (!all_accounts && account == NULL)
+ {
+ return;
+ }
+ else if (!all_accounts)
+ {
+ ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
+ _tpl_action_chain_append (window->chain, get_entities_for_account, ctx);
+ }
+ else
+ {
+ TpAccountManager *manager;
+ GList *accounts, *l;
+
+ manager = empathy_account_chooser_get_account_manager (account_chooser);
+ accounts = tp_account_manager_get_valid_accounts (manager);
+
+ for (l = accounts; l != NULL; l = l->next)
+ {
+ account = l->data;
+
+ ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
+ _tpl_action_chain_append (window->chain,
+ get_entities_for_account, ctx);
+ }
+
+ g_list_free (accounts);
+ }
+ _tpl_action_chain_append (window->chain, select_first_entity, NULL);
+ _tpl_action_chain_start (window->chain);
+}
- DEBUG ("Marking date: %04u-%02u-%02u", g_date_get_year (d),
- g_date_get_month (d), g_date_get_day (d));
+static gint
+sort_by_name (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gchar *name1, *name2;
+ gint type1, type2;
+ gint ret;
+
+ gtk_tree_model_get (model, a,
+ COL_WHO_TYPE, &type1,
+ COL_WHO_NAME, &name1,
+ -1);
+
+ gtk_tree_model_get (model, b,
+ COL_WHO_TYPE, &type2,
+ COL_WHO_NAME, &name2,
+ -1);
+
+ if (type1 == COL_TYPE_ANY)
+ ret = -1;
+ else if (type2 == COL_TYPE_ANY)
+ ret = 1;
+ else if (type1 == COL_TYPE_SEPARATOR)
+ ret = -1;
+ else if (type2 == COL_TYPE_SEPARATOR)
+ ret = 1;
+ else
+ ret = g_strcmp0 (name1, name2);
+
+ g_free (name1);
+ g_free (name2);
+
+ return ret;
+}
- gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats),
- g_date_get_day (d));
+static gboolean
+who_row_is_separator (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gint type;
- if (l->next) {
- continue;
- }
+ gtk_tree_model_get (model, iter,
+ COL_WHO_TYPE, &type,
+ -1);
- day_selected = TRUE;
+ return (type == COL_TYPE_SEPARATOR);
+}
- gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats),
- g_date_get_day (d));
- }
+static void
+log_window_events_setup (EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeSortable *sortable;
+ GtkTreeViewColumn *column;
+ GtkTreeStore *store;
+ GtkCellRenderer *cell;
+
+ view = GTK_TREE_VIEW (window->treeview_events);
+ selection = gtk_tree_view_get_selection (view);
+
+ /* new store */
+ window->store_events = store = gtk_tree_store_new (COL_EVENTS_COUNT,
+ G_TYPE_INT, /* type */
+ G_TYPE_INT64, /* timestamp */
+ G_TYPE_STRING, /* stringified date */
+ G_TYPE_STRING, /* icon */
+ G_TYPE_STRING, /* name */
+ TP_TYPE_ACCOUNT, /* account */
+ TPL_TYPE_ENTITY, /* target */
+ TPL_TYPE_EVENT); /* event */
+
+ 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_EVENTS_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_EVENTS_TEXT);
+
+ cell = gtk_cell_renderer_text_new ();
+ g_object_set (cell, "xalign", 1.0, NULL);
+ gtk_tree_view_column_pack_end (column, cell, FALSE);
+ gtk_tree_view_column_add_attribute (column, cell,
+ "text", COL_EVENTS_PRETTY_DATE);
+
+ gtk_tree_view_append_column (view, column);
+
+ /* set up treeview properties */
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
+ gtk_tree_view_set_headers_visible (view, FALSE);
+
+ gtk_tree_sortable_set_sort_column_id (sortable,
+ COL_EVENTS_TS,
+ GTK_SORT_ASCENDING);
+
+ g_object_unref (store);
+}
- if (!day_selected) {
- /* Unselect the day in the calendar */
- gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), 0);
- }
+static void
+log_window_who_setup (EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeSortable *sortable;
+ GtkTreeViewColumn *column;
+ GtkListStore *store;
+ GtkCellRenderer *cell;
+
+ view = GTK_TREE_VIEW (window->treeview_who);
+ selection = gtk_tree_view_get_selection (view);
+
+ /* new store */
+ store = gtk_list_store_new (COL_WHO_COUNT,
+ G_TYPE_INT, /* type */
+ G_TYPE_STRING, /* icon */
+ G_TYPE_STRING, /* name */
+ TP_TYPE_ACCOUNT, /* account */
+ TPL_TYPE_ENTITY); /* target */
+
+ 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 ();
+ gtk_tree_view_column_set_title (column, _("Who"));
+
+ 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_WHO_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_WHO_NAME);
+
+ gtk_tree_view_append_column (view, column);
+
+ /* set up treeview properties */
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ gtk_tree_view_set_row_separator_func (view, who_row_is_separator,
+ NULL, NULL);
+
+ gtk_tree_sortable_set_sort_column_id (sortable,
+ COL_WHO_NAME,
+ GTK_SORT_ASCENDING);
+ gtk_tree_sortable_set_sort_func (sortable,
+ COL_WHO_NAME, sort_by_name,
+ NULL, NULL);
+
+ /* set up signals */
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (log_window_who_changed_cb), window);
+
+ g_object_unref (store);
+}
- g_signal_handlers_unblock_by_func (window->calendar_chats,
- log_window_calendar_chats_day_selected_cb,
- window);
+static void
+log_window_chats_accounts_changed_cb (GtkWidget *combobox,
+ EmpathyLogWindow *window)
+{
+ /* Clear all current messages shown in the textview */
+ gtk_tree_store_clear (window->store_events);
- if (date != NULL) {
- /* Show messages of the most recent date */
- log_window_get_messages_for_date (window, date);
- }
+ log_window_who_populate (window);
+}
- g_list_foreach (dates, (GFunc) g_free, NULL);
- g_list_free (dates);
+static void
+log_window_chats_set_selected (EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gboolean next;
+
+ view = GTK_TREE_VIEW (window->treeview_who);
+ model = gtk_tree_view_get_model (view);
+ selection = gtk_tree_view_get_selection (view);
+
+ for (next = gtk_tree_model_get_iter_first (model, &iter);
+ next;
+ next = gtk_tree_model_iter_next (model, &iter))
+ {
+ TpAccount *this_account;
+ TplEntity *this_target;
+ const gchar *this_chat_id;
+ gboolean this_is_chatroom;
+
+ gtk_tree_model_get (model, &iter,
+ COL_WHO_ACCOUNT, &this_account,
+ COL_WHO_TARGET, &this_target,
+ -1);
+
+ this_chat_id = tpl_entity_get_identifier (this_target);
+ this_is_chatroom = tpl_entity_get_entity_type (this_target)
+ == TPL_ENTITY_ROOM;
+
+ if (this_account == window->selected_account &&
+ !tp_strdiff (this_chat_id, window->selected_chat_id) &&
+ this_is_chatroom == window->selected_is_chatroom)
+ {
+ gtk_tree_selection_select_iter (selection, &iter);
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
+ gtk_tree_path_free (path);
+ g_object_unref (this_account);
+ g_object_unref (this_target);
+ break;
+ }
+
+ g_object_unref (this_account);
+ g_object_unref (this_target);
+ }
+
+ tp_clear_object (&window->selected_account);
+ tp_clear_pointer (&window->selected_chat_id, g_free);
}
+static gint
+sort_by_date (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ GDate *date1, *date2;
-static void
-log_window_chats_get_messages (EmpathyLogWindow *window,
- GDate *date)
+ gtk_tree_model_get (model, a,
+ COL_WHEN_DATE, &date1,
+ -1);
+
+ gtk_tree_model_get (model, b,
+ COL_WHEN_DATE, &date2,
+ -1);
+
+ return g_date_compare (date1, date2);
+}
+
+static gboolean
+when_row_is_separator (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
{
- TpAccount *account;
- TplEntity *target;
- guint year_selected;
- guint month_selected;
- guint day;
+ gchar *when;
+ gboolean ret;
+ gtk_tree_model_get (model, iter,
+ COL_WHEN_TEXT, &when,
+ -1);
- if (!log_window_chats_get_selected (window, &account, &target)) {
- return;
- }
+ ret = g_str_equal (when, "separator");
+ g_free (when);
+ return ret;
+}
- g_signal_handlers_block_by_func (window->calendar_chats,
- log_window_calendar_chats_day_selected_cb,
- window);
+static void
+log_window_when_changed_cb (GtkTreeSelection *selection,
+ EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ DEBUG ("log_window_when_changed_cb");
+
+ view = gtk_tree_selection_get_tree_view (selection);
+ model = gtk_tree_view_get_model (view);
+
+ /* If 'Anytime' is selected, everything else should be deselected */
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ if (gtk_tree_selection_iter_is_selected (selection, &iter))
+ {
+ g_signal_handlers_block_by_func (selection,
+ log_window_when_changed_cb,
+ window);
+
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_when_changed_cb,
+ window);
+ }
+ }
+
+ log_window_chats_get_messages (window, FALSE);
+}
- /* Either use the supplied date or get the last */
- if (date == NULL) {
- /* Get a list of dates and show them on the calendar */
- tpl_log_manager_get_dates_async (window->log_manager,
- account, target, TPL_EVENT_MASK_TEXT,
- log_manager_got_dates_cb, (gpointer) window);
- /* signal unblocked at the end of the CB flow */
- } else {
- day = g_date_get_day (date);
- gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
- &year_selected,
- &month_selected,
- NULL);
+static void
+log_window_when_setup (EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeSortable *sortable;
+ GtkTreeViewColumn *column;
+ GtkListStore *store;
+ GtkCellRenderer *cell;
+
+ view = GTK_TREE_VIEW (window->treeview_when);
+ selection = gtk_tree_view_get_selection (view);
+
+ /* new store */
+ store = gtk_list_store_new (COL_WHEN_COUNT,
+ G_TYPE_DATE, /* date */
+ G_TYPE_STRING, /* stringified date */
+ G_TYPE_STRING); /* icon */
+
+ 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 ();
+ gtk_tree_view_column_set_title (column, _("When"));
+
+ 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_WHEN_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_WHEN_TEXT);
+
+ gtk_tree_view_append_column (view, column);
+
+ /* set up treeview properties */
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ gtk_tree_view_set_row_separator_func (view, when_row_is_separator,
+ NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (sortable,
+ COL_WHEN_DATE,
+ GTK_SORT_DESCENDING);
+ gtk_tree_sortable_set_sort_func (sortable,
+ COL_WHEN_DATE, sort_by_date,
+ NULL, NULL);
+
+ /* set up signals */
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (log_window_when_changed_cb),
+ window);
- month_selected++;
+ g_object_unref (store);
+}
- if (g_date_get_year (date) != year_selected &&
- g_date_get_month (date) != month_selected) {
- day = 0;
- }
+static gboolean
+what_row_is_separator (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gint type;
- gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day);
+ gtk_tree_model_get (model, iter,
+ COL_WHAT_TYPE, &type,
+ -1);
- g_signal_handlers_unblock_by_func (window->calendar_chats,
- log_window_calendar_chats_day_selected_cb,
- window);
- }
+ return (type == WHAT_TYPE_SEPARATOR);
+}
- if (date != NULL) {
- /* Show messages of the selected date */
- log_window_get_messages_for_date (window, date);
- }
+static void
+log_window_what_changed_cb (GtkTreeSelection *selection,
+ EmpathyLogWindow *window)
+{
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ DEBUG ("log_window_what_changed_cb");
+
+ view = gtk_tree_selection_get_tree_view (selection);
+ model = gtk_tree_view_get_model (view);
+
+ /* If 'Anything' is selected, everything else should be deselected */
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ if (gtk_tree_selection_iter_is_selected (selection, &iter))
+ {
+ g_signal_handlers_block_by_func (selection,
+ log_window_what_changed_cb,
+ window);
+
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_what_changed_cb,
+ window);
+ }
+ }
+
+ /* The dates need to be updated if we're not searching */
+ log_window_chats_get_messages (window, window->hits == NULL);
+}
- g_object_unref (account);
- g_object_unref (target);
+static gboolean
+log_window_what_collapse_row_cb (GtkTreeView *tree_view,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ gpointer user_data)
+{
+ /* Reject collapsing */
+ return TRUE;
}
+struct event
+{
+ gint type;
+ EventSubtype subtype;
+ const gchar *icon;
+ const gchar *text;
+};
+
static void
-log_window_calendar_chats_day_selected_cb (GtkWidget *calendar,
- EmpathyLogWindow *window)
+log_window_what_setup (EmpathyLogWindow *window)
{
- guint year;
- guint month;
- guint day;
- GDate *date;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeSortable *sortable;
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter, parent;
+ GtkTreeStore *store;
+ GtkCellRenderer *cell;
+ guint i;
+ struct event events [] = {
+ { TPL_EVENT_MASK_ANY, 0, NULL, _("Anything") },
+ { WHAT_TYPE_SEPARATOR, 0, NULL, "separator" },
+ { TPL_EVENT_MASK_TEXT, 0, "stock_text_justify", _("Text chats") },
+ { TPL_EVENT_MASK_CALL, EVENT_CALL_ALL, "call-start", _("Calls") }
+ };
+ struct event call_events [] = {
+ { TPL_EVENT_MASK_CALL, EVENT_CALL_INCOMING, "call-start", _("Incoming calls") },
+ { TPL_EVENT_MASK_CALL, EVENT_CALL_OUTGOING, "call-start", _("Outgoing calls") },
+ { TPL_EVENT_MASK_CALL, EVENT_CALL_MISSED, "call-stop", _("Missed calls") }
+ };
+
+ view = GTK_TREE_VIEW (window->treeview_what);
+ selection = gtk_tree_view_get_selection (view);
+
+ /* new store */
+ store = gtk_tree_store_new (COL_WHAT_COUNT,
+ G_TYPE_INT, /* history type */
+ G_TYPE_INT, /* history subtype */
+ G_TYPE_STRING, /* stringified history type */
+ G_TYPE_STRING, /* icon */
+ G_TYPE_BOOLEAN); /* expander (hidden) */
+
+ 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 ();
+ gtk_tree_view_column_set_title (column, _("What"));
+
+ 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_WHAT_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_WHAT_TEXT);
+
+ gtk_tree_view_append_column (view, column);
+
+ /* set up treeview properties */
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+ gtk_tree_view_set_show_expanders (view, FALSE);
+ gtk_tree_view_set_level_indentation (view, 12);
+ gtk_tree_view_expand_all (view);
+ gtk_tree_view_set_row_separator_func (view, what_row_is_separator,
+ NULL, NULL);
+
+ /* populate */
+ for (i = 0; i < G_N_ELEMENTS (events); i++)
+ {
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ COL_WHAT_TYPE, events[i].type,
+ COL_WHAT_SUBTYPE, events[i].subtype,
+ COL_WHAT_TEXT, events[i].text,
+ COL_WHAT_ICON, events[i].icon,
+ -1);
+ }
+
+ gtk_tree_model_iter_nth_child (model, &parent, NULL, 3);
+ for (i = 0; i < G_N_ELEMENTS (call_events); i++)
+ {
+ gtk_tree_store_append (store, &iter, &parent);
+ gtk_tree_store_set (store, &iter,
+ COL_WHAT_TYPE, call_events[i].type,
+ COL_WHAT_SUBTYPE, call_events[i].subtype,
+ COL_WHAT_TEXT, call_events[i].text,
+ COL_WHAT_ICON, call_events[i].icon,
+ -1);
+ }
+
+ gtk_tree_view_expand_all (view);
+
+ /* select 'Anything' */
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ /* set up signals */
+ g_signal_connect (view, "test-collapse-row",
+ G_CALLBACK (log_window_what_collapse_row_cb),
+ NULL);
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (log_window_what_changed_cb),
+ window);
- gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day);
- if (day == 0)
- /* No date selected */
- return;
+ g_object_unref (store);
+}
+
+static void
+log_window_got_messages_for_date_cb (GObject *manager,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Ctx *ctx = user_data;
+ GList *events;
+ GList *l;
+ GError *error = NULL;
- /* We need this hear because it appears that the months start from 0 */
- month++;
+ if (log_window == NULL)
+ goto out;
- date = g_date_new_dmy (day, month, year);
+ if (log_window->count != ctx->count)
+ goto out;
- DEBUG ("Currently selected date is: %04u-%02u-%02u", year, month, day);
+ if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (manager),
+ result, &events, &error))
+ {
+ DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting",
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ for (l = events; l; l = l->next)
+ {
+ TplEvent *event = l->data;
+ gboolean append = TRUE;
+
+ if (TPL_IS_CALL_EVENT (l->data)
+ && ctx->event_mask & TPL_EVENT_MASK_CALL
+ && ctx->event_mask != TPL_EVENT_MASK_ANY)
+ {
+ TplCallEvent *call = l->data;
+
+ append = FALSE;
+
+ if (ctx->subtype & EVENT_CALL_ALL)
+ {
+ append = TRUE;
+ }
+ else
+ {
+ TplCallEndReason reason = tpl_call_event_get_end_reason (call);
+ TplEntity *sender = tpl_event_get_sender (event);
+ TplEntity *receiver = tpl_event_get_receiver (event);
+
+ if (reason == TPL_CALL_END_REASON_NO_ANSWER)
+ {
+ if (ctx->subtype & EVENT_CALL_MISSED)
+ append = TRUE;
+ }
+ else if (ctx->subtype & EVENT_CALL_OUTGOING
+ && tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
+ {
+ append = TRUE;
+ }
+ else if (ctx->subtype & EVENT_CALL_INCOMING
+ && tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
+ {
+ append = TRUE;
+ }
+ }
+ }
+
+ if (append)
+ {
+ EmpathyMessage *msg = empathy_message_from_tpl_log_event (event);
+ log_window_append_message (event, msg);
+ g_object_unref (msg);
+ }
+
+ g_object_unref (event);
+ }
+ g_list_free (events);
- log_window_chats_get_messages (window, date);
+ out:
+ ctx_free (ctx);
- g_date_free (date);
+ _tpl_action_chain_continue (log_window->chain);
}
static void
-log_window_updating_calendar_month_cb (GObject *manager,
- GAsyncResult *result, gpointer user_data)
-{
- EmpathyLogWindow *window = user_data;
- GList *dates;
- GList *l;
- guint year_selected;
- guint month_selected;
- GError *error = NULL;
-
- if (log_window == NULL)
- return;
-
- if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager),
- result, &dates, &error)) {
- DEBUG ("Unable to retrieve messages' dates: %s. Aborting",
- error->message);
- empathy_chat_view_append_event (window->chatview_find,
- "Unable to retrieve messages' dates");
- g_error_free (error);
- return;
- }
-
- gtk_calendar_clear_marks (GTK_CALENDAR (window->calendar_chats));
- g_object_get (window->calendar_chats,
- "month", &month_selected,
- "year", &year_selected,
- NULL);
-
- /* We need this here because it appears that the months start from 0 */
- month_selected++;
-
- for (l = dates; l; l = l->next) {
- GDate *date = l->data;
-
- if (g_date_get_year (date) == year_selected &&
- g_date_get_month (date) == month_selected) {
- DEBUG ("Marking date: %04u-%02u-%02u", g_date_get_year (date),
- g_date_get_month (date), g_date_get_day (date));
- gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), g_date_get_day (date));
- }
- }
-
- g_list_foreach (dates, (GFunc) g_free, NULL);
- g_list_free (dates);
-
- DEBUG ("Currently showing month %d and year %d", month_selected,
- year_selected);
+get_events_for_date (TplActionChain *chain, gpointer user_data)
+{
+ Ctx *ctx = user_data;
+
+ tpl_log_manager_get_events_for_date_async (ctx->window->log_manager,
+ ctx->account, ctx->entity, ctx->event_mask,
+ ctx->date,
+ log_window_got_messages_for_date_cb,
+ ctx);
}
static void
-log_window_calendar_chats_month_changed_cb (GtkWidget *calendar,
- EmpathyLogWindow *window)
+log_window_get_messages_for_dates (EmpathyLogWindow *window,
+ GList *dates)
{
- TpAccount *account;
- TplEntity *target;
+ GList *accounts, *targets, *acc, *targ, *l;
+ TplEventTypeMask event_mask;
+ EventSubtype subtype;
+ GDate *date, *anytime, *separator;
+
+ if (!log_window_get_selected (window,
+ &accounts, &targets, NULL, &event_mask, &subtype))
+ return;
- gtk_calendar_clear_marks (GTK_CALENDAR (calendar));
+ anytime = g_date_new_dmy (2, 1, -1);
+ separator = g_date_new_dmy (1, 1, -1);
+
+ _tpl_action_chain_clear (window->chain);
+ window->count++;
+
+ for (acc = accounts, targ = targets;
+ acc != NULL && targ != NULL;
+ acc = acc->next, targ = targ->next)
+ {
+ TpAccount *account = acc->data;
+ TplEntity *target = targ->data;
+
+ for (l = dates; l != NULL; l = l->next)
+ {
+ date = l->data;
+
+ /* Get events */
+ if (g_date_compare (date, anytime) != 0)
+ {
+ Ctx *ctx;
+
+ ctx = ctx_new (window, account, target, date, event_mask, subtype,
+ window->count);
+ _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
+ }
+ else
+ {
+ GtkTreeView *view = GTK_TREE_VIEW (window->treeview_when);
+ GtkTreeModel *model = gtk_tree_view_get_model (view);
+ GtkTreeIter iter;
+ gboolean next;
+ GDate *d;
+
+ for (next = gtk_tree_model_get_iter_first (model, &iter);
+ next;
+ next = gtk_tree_model_iter_next (model, &iter))
+ {
+ Ctx *ctx;
+
+ gtk_tree_model_get (model, &iter,
+ COL_WHEN_DATE, &d,
+ -1);
+
+ if (g_date_compare (d, anytime) != 0 &&
+ g_date_compare (d, separator) != 0)
+ {
+ ctx = ctx_new (window, account, target, d,
+ event_mask, subtype, window->count);
+ _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
+ }
+ }
+ }
+ }
+ }
+
+ _tpl_action_chain_start (window->chain);
+
+ g_list_free_full (accounts, g_object_unref);
+ g_list_free_full (targets, g_object_unref);
+ g_date_free (separator);
+ g_date_free (anytime);
+}
- if (!log_window_chats_get_selected (window, &account, &target)) {
- DEBUG ("No chat selected to get dates for...");
- return;
- }
+static void
+log_manager_got_dates_cb (GObject *manager,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Ctx *ctx = user_data;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GList *dates;
+ GList *l;
+ GError *error = NULL;
- /* Get the log object for this contact */
- tpl_log_manager_get_dates_async (window->log_manager, account, target,
- TPL_EVENT_MASK_TEXT,
- log_window_updating_calendar_month_cb,
- (gpointer) window);
+ if (log_window == NULL)
+ goto out;
- g_object_unref (account);
- g_object_unref (target);
+ if (log_window->count != ctx->count)
+ goto out;
+
+ if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager),
+ result, &dates, &error))
+ {
+ DEBUG ("Unable to retrieve messages' dates: %s. Aborting",
+ error->message);
+ goto out;
+ }
+
+ view = GTK_TREE_VIEW (log_window->treeview_when);
+ model = gtk_tree_view_get_model (view);
+ store = GTK_LIST_STORE (model);
+ selection = gtk_tree_view_get_selection (view);
+
+ for (l = dates; l != NULL; l = l->next)
+ {
+ GDate *date = l->data;
+
+ /* Add the date if it's not already there */
+ has_element = FALSE;
+ gtk_tree_model_foreach (model, model_has_date, date);
+ if (!has_element)
+ {
+ gchar *text = format_date_for_display (date);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHEN_DATE, date,
+ COL_WHEN_TEXT, text,
+ COL_WHEN_ICON, CALENDAR_ICON,
+ -1);
+
+ g_free (text);
+ }
+ }
+
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ {
+ gchar *separator = NULL;
+
+ if (gtk_tree_model_iter_next (model, &iter))
+ {
+ gtk_tree_model_get (model, &iter,
+ COL_WHEN_TEXT, &separator,
+ -1);
+ }
+
+ if (g_strcmp0 (separator, "separator") != 0)
+ {
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
+ COL_WHEN_TEXT, "separator",
+ -1);
+
+ gtk_list_store_prepend (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
+ COL_WHEN_TEXT, _("Anytime"),
+ -1);
+ }
+ }
+
+ g_list_free_full (dates, g_free);
+ out:
+ ctx_free (ctx);
+ _tpl_action_chain_continue (log_window->chain);
}
static void
-log_window_entry_chats_changed_cb (GtkWidget *entry,
- EmpathyLogWindow *window)
+select_first_date (TplActionChain *chain, gpointer user_data)
{
- const gchar *str;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ view = GTK_TREE_VIEW (log_window->treeview_when);
+ model = gtk_tree_view_get_model (view);
+ selection = gtk_tree_view_get_selection (view);
- str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
- empathy_chat_view_highlight (window->chatview_chats, str, FALSE);
+ /* Show messages of the most recent date */
+ if (gtk_tree_model_get_iter_first (model, &iter))
+ gtk_tree_selection_select_iter (selection, &iter);
- if (str != NULL) {
- empathy_chat_view_find_next (window->chatview_chats,
- str,
- TRUE,
- FALSE);
- }
+ _tpl_action_chain_continue (log_window->chain);
}
static void
-log_window_entry_chats_activate_cb (GtkWidget *entry,
- EmpathyLogWindow *window)
+get_dates_for_entity (TplActionChain *chain, gpointer user_data)
{
- const gchar *str;
+ Ctx *ctx = user_data;
- str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
+ tpl_log_manager_get_dates_async (ctx->window->log_manager,
+ ctx->account, ctx->entity, ctx->event_mask,
+ log_manager_got_dates_cb, ctx);
+}
+
+static void
+log_window_chats_get_messages (EmpathyLogWindow *window,
+ gboolean force_get_dates)
+{
+ GList *accounts, *targets, *dates;
+ TplEventTypeMask event_mask;
+ GtkTreeView *view;
+ GtkTreeModel *model;
+ GtkListStore *store;
+ GtkTreeSelection *selection;
+
+ if (!log_window_get_selected (window, &accounts, &targets,
+ &dates, &event_mask, NULL))
+ return;
- if (str != NULL) {
- empathy_chat_view_find_next (window->chatview_chats,
- str,
- FALSE,
- FALSE);
- }
+ view = GTK_TREE_VIEW (window->treeview_when);
+ selection = gtk_tree_view_get_selection (view);
+ model = gtk_tree_view_get_model (view);
+ store = GTK_LIST_STORE (model);
+
+ /* Clear all current messages shown in the textview */
+ gtk_tree_store_clear (window->store_events);
+
+ _tpl_action_chain_clear (window->chain);
+ window->count++;
+
+ /* If there's a search use the returned hits */
+ if (window->hits != NULL)
+ {
+ if (force_get_dates)
+ {
+ g_signal_handlers_block_by_func (selection,
+ log_window_when_changed_cb,
+ window);
+
+ gtk_list_store_clear (store);
+
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_when_changed_cb,
+ window);
+
+ populate_dates_from_search_hits (accounts, targets);
+ }
+ else
+ {
+ populate_events_from_search_hits (accounts, targets, dates);
+ }
+ }
+ /* Either use the supplied date or get the last */
+ else if (force_get_dates || dates == NULL)
+ {
+ GList *acc, *targ;
+
+ g_signal_handlers_block_by_func (selection,
+ log_window_when_changed_cb,
+ window);
+
+ gtk_list_store_clear (store);
+
+ g_signal_handlers_unblock_by_func (selection,
+ log_window_when_changed_cb,
+ window);
+
+ /* Get a list of dates and show them on the treeview */
+ for (targ = targets, acc = accounts;
+ targ != NULL && acc != NULL;
+ targ = targ->next, acc = acc->next)
+ {
+ TpAccount *account = acc->data;
+ TplEntity *target = targ->data;
+ Ctx *ctx = ctx_new (window, account, target, NULL, event_mask, 0,
+ window->count);
+
+ _tpl_action_chain_append (window->chain, get_dates_for_entity, ctx);
+ }
+ _tpl_action_chain_append (window->chain, select_first_date, NULL);
+ _tpl_action_chain_start (window->chain);
+ }
+ else
+ {
+ /* Show messages of the selected date */
+ log_window_get_messages_for_dates (window, dates);
+ }
+
+ g_list_free_full (accounts, g_object_unref);
+ g_list_free_full (targets, g_object_unref);
+ g_list_free_full (dates, (GFreeFunc) g_date_free);
}
typedef struct {
- EmpathyAccountChooserFilterResultCallback callback;
- gpointer user_data;
+ EmpathyAccountChooserFilterResultCallback callback;
+ gpointer user_data;
} FilterCallbackData;
static void
-got_entities (GObject *manager,
- GAsyncResult *result,
- gpointer user_data)
+got_entities (GObject *manager,
+ GAsyncResult *result,
+ gpointer user_data)
{
- FilterCallbackData *data = user_data;
- GList *entities;
- GError *error;
+ FilterCallbackData *data = user_data;
+ GList *entities;
+ GError *error = NULL;
- if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager), result, &entities, &error)) {
- DEBUG ("Could not get entities: %s", error->message);
- g_error_free (error);
- data->callback (FALSE, data->user_data);
- } else {
- data->callback (entities != NULL, data->user_data);
+ if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
+ result, &entities, &error))
+ {
+ DEBUG ("Could not get entities: %s", error->message);
+ g_error_free (error);
+ data->callback (FALSE, data->user_data);
+ }
+ else
+ {
+ data->callback (entities != NULL, data->user_data);
- g_list_free_full (entities, g_object_unref);
- }
+ g_list_free_full (entities, g_object_unref);
+ }
- g_slice_free (FilterCallbackData, data);
+ g_slice_free (FilterCallbackData, data);
}
static void
empathy_account_chooser_filter_has_logs (TpAccount *account,
- EmpathyAccountChooserFilterResultCallback callback,
- gpointer callback_data,
- gpointer user_data)
+ EmpathyAccountChooserFilterResultCallback callback,
+ gpointer callback_data,
+ gpointer user_data)
{
- TplLogManager *manager = tpl_log_manager_dup_singleton ();
- FilterCallbackData *cb_data = g_slice_new0 (FilterCallbackData);
+ TplLogManager *manager = tpl_log_manager_dup_singleton ();
+ FilterCallbackData *cb_data = g_slice_new0 (FilterCallbackData);
- cb_data->callback = callback;
- cb_data->user_data = callback_data;
+ cb_data->callback = callback;
+ cb_data->user_data = callback_data;
- tpl_log_manager_get_entities_async (manager, account, got_entities, cb_data);
+ tpl_log_manager_get_entities_async (manager, account, got_entities, cb_data);
- g_object_unref (manager);
+ g_object_unref (manager);
}
static void
log_window_logger_clear_account_cb (TpProxy *proxy,
- const GError *error,
- gpointer user_data,
- GObject *weak_object)
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
{
- EmpathyLogWindow *window = user_data;
+ EmpathyLogWindow *window = user_data;
- if (error != NULL)
- g_warning ("Error when clearing logs: %s", error->message);
+ if (error != NULL)
+ g_warning ("Error when clearing logs: %s", error->message);
- /* Refresh the log viewer so the logs are cleared if the account
- * has been deleted */
- empathy_chat_view_clear (window->chatview_chats);
- log_window_chats_populate (window);
+ /* Refresh the log viewer so the logs are cleared if the account
+ * has been deleted */
+ gtk_tree_store_clear (window->store_events);
+ log_window_who_populate (window);
- /* Re-filter the account chooser so the accounts without logs get greyed out */
- empathy_account_chooser_set_filter (EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats),
- empathy_account_chooser_filter_has_logs, NULL);
+ /* Re-filter the account chooser so the accounts without logs get greyed out */
+ empathy_account_chooser_set_filter (
+ EMPATHY_ACCOUNT_CHOOSER (window->account_chooser),
+ empathy_account_chooser_filter_has_logs, NULL);
}
static void
log_window_clear_logs_chooser_select_account (EmpathyAccountChooser *chooser,
- EmpathyLogWindow *window)
+ EmpathyLogWindow *window)
{
- empathy_account_chooser_set_account (chooser,
- empathy_account_chooser_get_account (EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats)));
+ EmpathyAccountChooser *account_chooser;
+
+ account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
+
+ empathy_account_chooser_set_account (chooser,
+ empathy_account_chooser_get_account (account_chooser));
}
static void
-log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
- EmpathyLogWindow *window)
-{
- GtkWidget *dialog, *content_area, *hbox, *label;
- EmpathyAccountChooser *account_chooser;
- gint response_id;
- TpDBusDaemon *bus;
- TpProxy *logger;
- GError *error = NULL;
-
- account_chooser = (EmpathyAccountChooser *) empathy_account_chooser_new ();
- empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
- empathy_account_chooser_set_filter (account_chooser, empathy_account_chooser_filter_has_logs, NULL);
-
- /* Select the same account as in the history window */
- if (empathy_account_chooser_is_ready (account_chooser))
- log_window_clear_logs_chooser_select_account (account_chooser, window);
- else
- g_signal_connect (account_chooser, "ready",
- G_CALLBACK (log_window_clear_logs_chooser_select_account), window);
-
- dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window->window),
- GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
- GTK_BUTTONS_NONE,
- _("Are you sure you want to delete all logs of previous conversations?"));
-
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- _("Clear All"), GTK_RESPONSE_APPLY,
- NULL);
-
- content_area = gtk_message_dialog_get_message_area (
- GTK_MESSAGE_DIALOG (dialog));
-
- hbox = gtk_hbox_new (FALSE, 6);
- label = gtk_label_new (_("Delete from:"));
- gtk_box_pack_start (GTK_BOX (hbox), label,
- FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (account_chooser),
- FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (content_area), hbox,
- FALSE, FALSE, 0);
-
- gtk_widget_show_all (hbox);
-
- response_id = gtk_dialog_run (GTK_DIALOG (dialog));
-
- if (response_id != GTK_RESPONSE_APPLY)
- goto out;
-
- bus = tp_dbus_daemon_dup (&error);
- if (error != NULL) {
- g_warning ("Could not delete logs: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- logger = g_object_new (TP_TYPE_PROXY,
- "bus-name", "org.freedesktop.Telepathy.Logger",
- "object-path", "/org/freedesktop/Telepathy/Logger",
- "dbus-daemon", bus,
- NULL);
- g_object_unref (bus);
-
- tp_proxy_add_interface_by_id (logger, EMP_IFACE_QUARK_LOGGER);
-
- if (empathy_account_chooser_has_all_selected (account_chooser)) {
- DEBUG ("Deleting logs for all the accounts");
-
- emp_cli_logger_call_clear (logger, -1,
- log_window_logger_clear_account_cb,
- window, NULL, G_OBJECT (window->window));
- } else {
- TpAccount *account = empathy_account_chooser_get_account (account_chooser);
-
- DEBUG ("Deleting logs for %s", tp_proxy_get_object_path (account));
-
- emp_cli_logger_call_clear_account (logger, -1,
- tp_proxy_get_object_path (account),
- log_window_logger_clear_account_cb,
- window, NULL, G_OBJECT (window->window));
- }
-
- g_object_unref (logger);
+log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
+ EmpathyLogWindow *window)
+{
+ GtkWidget *dialog, *content_area, *hbox, *label;
+ EmpathyAccountChooser *account_chooser;
+ gint response_id;
+ TpDBusDaemon *bus;
+ TpProxy *logger;
+ GError *error = NULL;
+
+ account_chooser = (EmpathyAccountChooser *) empathy_account_chooser_new ();
+ empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
+ empathy_account_chooser_set_filter (account_chooser,
+ empathy_account_chooser_filter_has_logs, NULL);
+
+ /* Select the same account as in the history window */
+ if (empathy_account_chooser_is_ready (account_chooser))
+ log_window_clear_logs_chooser_select_account (account_chooser, window);
+ else
+ g_signal_connect (account_chooser, "ready",
+ G_CALLBACK (log_window_clear_logs_chooser_select_account), window);
+
+ dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window->window),
+ GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ _("Are you sure you want to delete all logs of previous conversations?"));
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ _("Clear All"), GTK_RESPONSE_APPLY,
+ NULL);
+
+ content_area = gtk_message_dialog_get_message_area (
+ GTK_MESSAGE_DIALOG (dialog));
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ label = gtk_label_new (_("Delete from:"));
+ gtk_box_pack_start (GTK_BOX (hbox), label,
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (account_chooser),
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (content_area), hbox,
+ FALSE, FALSE, 0);
+
+ gtk_widget_show_all (hbox);
+
+ response_id = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response_id != GTK_RESPONSE_APPLY)
+ goto out;
+
+ bus = tp_dbus_daemon_dup (&error);
+ if (error != NULL)
+ {
+ g_warning ("Could not delete logs: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ logger = g_object_new (TP_TYPE_PROXY,
+ "bus-name", "org.freedesktop.Telepathy.Logger",
+ "object-path", "/org/freedesktop/Telepathy/Logger",
+ "dbus-daemon", bus,
+ NULL);
+ g_object_unref (bus);
+
+ tp_proxy_add_interface_by_id (logger, EMP_IFACE_QUARK_LOGGER);
+
+ if (empathy_account_chooser_has_all_selected (account_chooser))
+ {
+ DEBUG ("Deleting logs for all the accounts");
+
+ emp_cli_logger_call_clear (logger, -1,
+ log_window_logger_clear_account_cb,
+ window, NULL, G_OBJECT (window->window));
+ }
+ else
+ {
+ TpAccount *account;
+
+ account = empathy_account_chooser_get_account (account_chooser);
+
+ DEBUG ("Deleting logs for %s", tp_proxy_get_object_path (account));
+
+ emp_cli_logger_call_clear_account (logger, -1,
+ tp_proxy_get_object_path (account),
+ log_window_logger_clear_account_cb,
+ window, NULL, G_OBJECT (window->window));
+ }
+
+ g_object_unref (logger);
out:
- gtk_widget_destroy (dialog);
+ gtk_widget_destroy (dialog);
}
diff --git a/libempathy-gtk/empathy-log-window.h b/libempathy-gtk/empathy-log-window.h
index def0d846b..373f48c36 100644
--- a/libempathy-gtk/empathy-log-window.h
+++ b/libempathy-gtk/empathy-log-window.h
@@ -1,7 +1,6 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2006-2007 Imendio AB
- * Copyright (C) 2007-2008 Collabora Ltd.
+ * Copyright (C) 2007-2011 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
@@ -20,6 +19,7 @@
*
* Authors: Martyn Russell <martyn@imendio.com>
* Xavier Claessens <xclaesse@gmail.com>
+ * Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
*/
#ifndef __EMPATHY_LOG_WINDOW_H__
@@ -29,10 +29,10 @@
G_BEGIN_DECLS
-GtkWidget * empathy_log_window_show (TpAccount *account,
- const gchar *chat_id,
- gboolean chatroom,
- GtkWindow *parent);
+GtkWidget * empathy_log_window_show (TpAccount *account,
+ const gchar *chat_id,
+ gboolean chatroom,
+ GtkWindow *parent);
G_END_DECLS
diff --git a/libempathy-gtk/empathy-log-window.ui b/libempathy-gtk/empathy-log-window.ui
index 499bff999..9b5ab9551 100644
--- a/libempathy-gtk/empathy-log-window.ui
+++ b/libempathy-gtk/empathy-log-window.ui
@@ -1,13 +1,11 @@
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
- <!-- interface-naming-policy toplevel-contextual -->
+ <!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="log_window">
- <property name="title" translatable="yes">Previous Conversations</property>
- <property name="role">log</property>
- <property name="default_width">640</property>
- <property name="default_height">450</property>
- <property name="icon_name">document-open-recent</property>
+ <property name="title" translatable="yes">History</property>
+ <property name="default_width">800</property>
+ <property name="default_height">600</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
@@ -16,6 +14,26 @@
<object class="GtkMenuBar" id="menubar1">
<property name="visible">True</property>
<child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem_quit">
+ <property name="label">gtk-quit</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
<object class="GtkMenuItem" id="menuitem2">
<property name="visible">True</property>
<property name="label" translatable="yes">_Edit</property>
@@ -24,10 +42,10 @@
<object class="GtkMenu" id="menu2">
<property name="visible">True</property>
<child>
- <object class="GtkImageMenuItem" id="menu_delete">
- <property name="label" translatable="yes">Delete All History...</property>
+ <object class="GtkImageMenuItem" id="imagemenuitem_delete">
+ <property name="label">Delete All History...</property>
<property name="visible">True</property>
- <property name="image">image3</property>
+ <property name="image">image1</property>
<property name="use_stock">False</property>
</object>
</child>
@@ -42,322 +60,191 @@
</packing>
</child>
<child>
- <object class="GtkNotebook" id="notebook">
+ <object class="GtkToolbar" id="toolbar1">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="border_width">2</property>
+ <property name="toolbar_style">both</property>
<child>
- <object class="GtkVBox" id="vbox192">
+ <object class="GtkToolButton" id="toolbutton_profile">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Profile</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-dialog-info</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="toolbutton_chat">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Chat</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-edit</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="toolbutton_call">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Call</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">audio-input-microphone</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="toolbutton_video">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Video</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">camera-video</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="toolbutton_sep1">
+ <property name="visible">True</property>
+ <property name="draw">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolItem" id="toolbutton_accounts">
<property name="visible">True</property>
- <property name="border_width">12</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkHBox" id="hbox144">
- <property name="visible">True</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label628">
- <property name="visible">True</property>
- <property name="label" translatable="yes" comments="Searching *for* something">_For:</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">entry_find</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_find">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">&#x25CF;</property>
- <property name="activates_default">True</property>
- </object>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="button_find">
- <property name="label">gtk-find</property>
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="receives_default">True</property>
- <property name="use_stock">True</property>
- <property name="focus_on_click">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
<child>
- <object class="GtkVPaned" id="vpaned1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="orientation">vertical</property>
- <property name="position">120</property>
- <property name="position_set">True</property>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow14">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="treeview_find">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="enable_search">False</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="resize">False</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- <child>
- <object class="GtkVBox" id="vbox215">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow_find">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkHBox" id="hbox171">
- <property name="visible">True</property>
- <property name="spacing">12</property>
- <child>
- <placeholder/>
- </child>
- <child>
- <object class="GtkButton" id="button_next">
- <property name="label" translatable="yes">Find Next</property>
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="image">image1</property>
- <property name="focus_on_click">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="button_previous">
- <property name="label" translatable="yes">Find Previous</property>
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="image">image2</property>
- <property name="focus_on_click">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="pack_type">end</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="resize">True</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="position">120</property>
- </packing>
+ <placeholder/>
</child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
</child>
- <child type="tab">
- <object class="GtkLabel" id="label595">
+ <child>
+ <object class="GtkSeparatorToolItem" id="toolbutton_sep2">
<property name="visible">True</property>
- <property name="label" translatable="yes" comments="Tab Label">Search</property>
+ <property name="draw">False</property>
</object>
<packing>
- <property name="tab_fill">False</property>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
</packing>
</child>
<child>
- <object class="GtkTable" id="table7">
+ <object class="GtkToolItem" id="toolbutton_search">
<property name="visible">True</property>
- <property name="border_width">12</property>
- <property name="n_rows">2</property>
- <property name="n_columns">2</property>
- <property name="column_spacing">6</property>
- <property name="row_spacing">6</property>
<child>
- <object class="GtkHBox" id="hbox_chats">
- <property name="visible">True</property>
- <property name="spacing">6</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
+ <placeholder/>
</child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="height_request">160</property>
+ <property name="visible">True</property>
<child>
- <object class="GtkScrolledWindow" id="scrolledwindow_chats">
+ <object class="GtkScrolledWindow" id="scrolledwindow_who">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
+ <property name="hscrollbar_policy">automatic</property>
<child>
- <placeholder/>
+ <object class="GtkTreeView" id="treeview_who">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
</child>
</object>
<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>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkVBox" id="vbox191">
+ <object class="GtkScrolledWindow" id="scrolledwindow_what">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object 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">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="treeview_chats">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="headers_visible">False</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="position">0</property>
- </packing>
- </child>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
<child>
- <object class="GtkCalendar" id="calendar_chats">
+ <object class="GtkTreeView" id="treeview_what">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="year">2011</property>
- <property name="month">2</property>
- <property name="day">15</property>
- <property name="sensitive">False</property>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
<packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">GTK_FILL</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkHBox" id="hbox143">
+ <object class="GtkScrolledWindow" id="scrolledwindow_when">
<property name="visible">True</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image247">
- <property name="visible">True</property>
- <property name="stock">gtk-find</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
<child>
- <object class="GtkEntry" id="entry_chats">
+ <object class="GtkTreeView" id="treeview_when">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="invisible_char">&#x25CF;</property>
- <property name="activates_default">True</property>
</object>
- <packing>
- <property name="position">1</property>
- </packing>
</child>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
<packing>
- <property name="position">1</property>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
</packing>
</child>
- <child type="tab">
- <object class="GtkLabel" id="label596">
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow_events">
<property name="visible">True</property>
- <property name="label" translatable="yes" comments="Tab Label">Conversations</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="treeview_events">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
</object>
<packing>
- <property name="position">1</property>
- <property name="tab_fill">False</property>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
</packing>
</child>
</object>
<packing>
- <property name="position">1</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
@@ -365,14 +252,6 @@
</object>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
- <property name="stock">gtk-go-forward</property>
- </object>
- <object class="GtkImage" id="image2">
- <property name="visible">True</property>
- <property name="stock">gtk-go-back</property>
- </object>
- <object class="GtkImage" id="image3">
- <property name="visible">True</property>
<property name="stock">gtk-missing-image</property>
</object>
</interface>
diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am
index 95c561261..571980dd8 100644
--- a/libempathy/Makefile.am
+++ b/libempathy/Makefile.am
@@ -26,6 +26,7 @@ BUILT_SOURCES = \
noinst_LTLIBRARIES = libempathy.la
libempathy_headers = \
+ action-chain-internal.h \
empathy-account-settings.h \
empathy-auth-factory.h \
empathy-channel-factory.h \
@@ -67,6 +68,7 @@ libempathy_headers = \
libempathy_la_SOURCES = \
$(libempathy_headers) \
+ action-chain.c \
empathy-account-settings.c \
empathy-auth-factory.c \
empathy-channel-factory.c \
diff --git a/libempathy/action-chain-internal.h b/libempathy/action-chain-internal.h
new file mode 100644
index 000000000..14750c938
--- /dev/null
+++ b/libempathy/action-chain-internal.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#ifndef __TPL_ACTION_CHAIN_H__
+#define __TPL_ACTION_CHAIN_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+typedef struct {
+ GQueue *chain;
+ GSimpleAsyncResult *simple;
+ gboolean running;
+} TplActionChain;
+
+TplActionChain *_tpl_action_chain_new_async (GObject *obj,
+ GAsyncReadyCallback cb,
+ gpointer user_data);
+void _tpl_action_chain_free (TplActionChain *self);
+typedef void (*TplPendingAction) (TplActionChain *ctx, gpointer user_data);
+void _tpl_action_chain_append (TplActionChain *self, TplPendingAction func,
+ gpointer user_data);
+void _tpl_action_chain_prepend (TplActionChain *self, TplPendingAction func,
+ gpointer user_data);
+void _tpl_action_chain_start (TplActionChain *self);
+void _tpl_action_chain_continue (TplActionChain *self);
+void _tpl_action_chain_terminate (TplActionChain *self, const GError *error);
+void _tpl_action_chain_clear (TplActionChain *self);
+
+gpointer _tpl_action_chain_get_object (TplActionChain *self);
+gboolean _tpl_action_chain_new_finish (GObject *source,
+ GAsyncResult *result, GError **error);
+
+#endif // __TPL_ACTION_CHAIN_H__
diff --git a/libempathy/action-chain.c b/libempathy/action-chain.c
new file mode 100644
index 000000000..b6bf25ab9
--- /dev/null
+++ b/libempathy/action-chain.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ */
+
+#include "config.h"
+#include "action-chain-internal.h"
+
+typedef struct {
+ TplPendingAction action;
+ gpointer user_data;
+} TplActionLink;
+
+
+TplActionChain *
+_tpl_action_chain_new_async (GObject *obj,
+ GAsyncReadyCallback cb,
+ gpointer user_data)
+{
+ TplActionChain *ret = g_slice_new0 (TplActionChain);
+
+ ret->chain = g_queue_new ();
+ ret->simple = g_simple_async_result_new (obj, cb, user_data,
+ _tpl_action_chain_new_async);
+
+ g_object_set_data (G_OBJECT (ret->simple), "chain", ret);
+
+ return ret;
+}
+
+
+static void
+link_free (TplActionLink *l)
+{
+ g_slice_free (TplActionLink, l);
+}
+
+
+void
+_tpl_action_chain_free (TplActionChain *self)
+{
+ g_queue_foreach (self->chain, (GFunc) link_free, NULL);
+ g_queue_free (self->chain);
+ g_object_unref (self->simple);
+ g_slice_free (TplActionChain, self);
+}
+
+
+gpointer // FIXME GObject *
+_tpl_action_chain_get_object (TplActionChain *self)
+{
+ GObject *obj;
+
+ g_return_val_if_fail (self != NULL && self->simple != NULL, NULL);
+
+ obj = g_async_result_get_source_object (G_ASYNC_RESULT (self->simple));
+ g_object_unref (obj); /* don't want the extra ref */
+
+ return obj;
+}
+
+
+void
+_tpl_action_chain_prepend (TplActionChain *self,
+ TplPendingAction func,
+ gpointer user_data)
+{
+ TplActionLink *l;
+
+ l = g_slice_new0 (TplActionLink);
+ l->action = func;
+ l->user_data = user_data;
+
+ g_queue_push_head (self->chain, l);
+}
+
+
+void
+_tpl_action_chain_append (TplActionChain *self,
+ TplPendingAction func,
+ gpointer user_data)
+{
+ TplActionLink *l;
+
+ l = g_slice_new0 (TplActionLink);
+ l->action = func;
+ l->user_data = user_data;
+
+ g_queue_push_tail (self->chain, l);
+}
+
+void
+_tpl_action_chain_start (TplActionChain *self)
+{
+ g_return_if_fail (!g_queue_is_empty (self->chain));
+
+ if (self->running)
+ return;
+
+ _tpl_action_chain_continue (self);
+}
+
+void
+_tpl_action_chain_continue (TplActionChain *self)
+{
+ if (g_queue_is_empty (self->chain))
+ {
+ self->running = FALSE;
+ g_simple_async_result_complete (self->simple);
+ }
+ else
+ {
+ TplActionLink *l = g_queue_pop_head (self->chain);
+
+ self->running = TRUE;
+ l->action (self, l->user_data);
+ link_free (l);
+ if (g_queue_is_empty (self->chain))
+ self->running = FALSE;
+ }
+}
+
+
+void
+_tpl_action_chain_clear (TplActionChain *self)
+{
+ g_queue_foreach (self->chain, (GFunc) link_free, NULL);
+ g_queue_clear (self->chain);
+}
+
+void
+_tpl_action_chain_terminate (TplActionChain *self,
+ const GError *error)
+{
+ GSimpleAsyncResult *simple = self->simple;
+
+ g_assert (error != NULL);
+
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete (simple);
+}
+
+
+/**
+ * _tpl_action_chain_new_finish:
+ * @source: the #GObject pass to _tpl_action_chain_new_async()
+ * @result: the #GAsyncResult pass in callback
+ * @error: a pointer to a #GError that will be set on error, or NULL to ignore
+ *
+ * Get the result from running the action chain (%TRUE if the chain completed
+ * successfully, %FALSE with @error set if it was terminated).
+ *
+ * This function also frees the chain.
+ *
+ * Returns: %TRUE on success, %FALSE with @error set on error.
+ */
+gboolean
+_tpl_action_chain_new_finish (GObject *source,
+ GAsyncResult *result,
+ GError **error)
+{
+ TplActionChain *chain;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, source,
+ _tpl_action_chain_new_async), FALSE);
+
+ chain = g_object_get_data (G_OBJECT (result), "chain");
+
+ g_return_val_if_fail (chain != NULL, FALSE);
+
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
+ error))
+ return FALSE;
+
+ _tpl_action_chain_free (chain);
+ return TRUE;
+}
diff --git a/libempathy/empathy-message.c b/libempathy/empathy-message.c
index 076a10053..15999dcdd 100644
--- a/libempathy/empathy-message.c
+++ b/libempathy/empathy-message.c
@@ -26,6 +26,8 @@
#include <string.h>
+#include <glib/gi18n-lib.h>
+
#include <telepathy-glib/util.h>
#include <telepathy-glib/account.h>
#include <telepathy-glib/account-manager.h>
@@ -33,6 +35,7 @@
#include <telepathy-logger/entity.h>
#include <telepathy-logger/event.h>
#include <telepathy-logger/text-event.h>
+#include <telepathy-logger/call-event.h>
#include "empathy-message.h"
#include "empathy-utils.h"
@@ -302,29 +305,42 @@ empathy_message_from_tpl_log_event (TplEvent *logevent)
tpl_event_get_account_path (logevent));
g_object_unref (acc_man);
- /* TODO Currently only TplTextEvent exists as subclass of TplEvent, in
- * future more TplEvent will exist and EmpathyMessage should probably
- * be enhanced to support other types of log entries (ie TplCallEvent).
- *
- * For now we just check (simply) that we are dealing with the only supported type,
- * then there will be a if/then/else or switch handling all the supported
- * cases.
- */
- if (!TPL_IS_TEXT_EVENT (logevent))
+ if (TPL_IS_TEXT_EVENT (logevent)) {
+ body = g_strdup (tpl_text_event_get_message (
+ TPL_TEXT_EVENT (logevent)));
+
+ retval = g_object_new (EMPATHY_TYPE_MESSAGE,
+ "type", tpl_text_event_get_message_type (TPL_TEXT_EVENT (logevent)),
+ "body", body,
+ "timestamp", tpl_event_get_timestamp (logevent),
+ "is-backlog", TRUE,
+ NULL);
+
+ g_free (body);
+ } else if (TPL_IS_CALL_EVENT (logevent)) {
+ TplCallEvent *call = TPL_CALL_EVENT (logevent);
+ if (tpl_call_event_get_end_reason (call) == TPL_CALL_END_REASON_NO_ANSWER)
+ body = g_strdup_printf (_("Missed call from %s"),
+ tpl_entity_get_alias (tpl_event_get_sender (logevent)));
+ else if (tpl_entity_get_entity_type (tpl_event_get_sender (logevent)) == TPL_ENTITY_SELF)
+ body = g_strdup_printf (_("Called %s"),
+ tpl_entity_get_alias (tpl_event_get_receiver (logevent)));
+ else
+ body = g_strdup_printf (_("Call from %s"),
+ tpl_entity_get_alias (tpl_event_get_sender (logevent)));
+
+ retval = g_object_new (EMPATHY_TYPE_MESSAGE,
+ "body", body,
+ "timestamp", tpl_event_get_timestamp (logevent),
+ NULL);
+ g_free (body);
+ } else {
return NULL;
+ }
- body = g_strdup (tpl_text_event_get_message (
- TPL_TEXT_EVENT (logevent)));
receiver = tpl_event_get_receiver (logevent);
sender = tpl_event_get_sender (logevent);
- retval = g_object_new (EMPATHY_TYPE_MESSAGE,
- "type", tpl_text_event_get_message_type (TPL_TEXT_EVENT (logevent)),
- "body", body,
- "is-backlog", TRUE,
- "timestamp", tpl_event_get_timestamp (logevent),
- NULL);
-
if (receiver != NULL) {
contact = empathy_contact_from_tpl_contact (account, receiver);
empathy_message_set_receiver (retval, contact);
@@ -337,8 +353,6 @@ empathy_message_from_tpl_log_event (TplEvent *logevent)
g_object_unref (contact);
}
- g_free (body);
-
return retval;
}
diff --git a/libempathy/empathy-utils.c b/libempathy/empathy-utils.c
index 8d4cd8d68..dfc2595c3 100644
--- a/libempathy/empathy-utils.c
+++ b/libempathy/empathy-utils.c
@@ -409,18 +409,33 @@ empathy_account_get_error_message (TpAccount *account,
{
const gchar *dbus_error;
const gchar *message;
- const GHashTable *details = NULL;
+ const GHashTable *details = NULL;
TpConnectionStatusReason reason;
+ guint skype_reason;
+ gboolean skype_reason_valid;
dbus_error = tp_account_get_detailed_error (account, &details);
- if (user_requested != NULL)
- {
- if (tp_asv_get_boolean (details, "user-requested", NULL))
- *user_requested = TRUE;
- else
- *user_requested = FALSE;
- }
+ if (user_requested != NULL)
+ {
+ if (tp_asv_get_boolean (details, "user-requested", NULL))
+ *user_requested = TRUE;
+ else
+ *user_requested = FALSE;
+ }
+
+ /* Skype certification requires us to return the precise error message.
+ * Check to see if skype-reason is defined, if it is, try to use that
+ * over the dbus error message */
+ skype_reason = tp_asv_get_uint32 (details, "skype-reason",
+ &skype_reason_valid);
+
+ if (skype_reason_valid)
+ {
+ message = empathy_skype_reason_to_string (skype_reason);
+ if (message != NULL)
+ return message;
+ }
message = empathy_dbus_error_name_get_default_message (dbus_error);
if (message != NULL)
@@ -871,3 +886,63 @@ empathy_format_currency (gint amount,
return money;
}
+const gchar *
+empathy_skype_reason_to_string (guint skype_reason)
+{
+ switch (skype_reason)
+ {
+ case EMP_SKYPE_LOGOUTREASON_NONE:
+ return _("No Reason");
+ case EMP_SKYPE_LOGOUTREASON_LOGOUT_CALLED:
+ return _("Requested");
+ case EMP_SKYPE_LOGOUTREASON_HTTPS_PROXY_AUTH_FAILED:
+ return _("HTTPS proxy authentication failed");
+ case EMP_SKYPE_LOGOUTREASON_SOCKS_PROXY_AUTH_FAILED:
+ return _("SOCKS proxy authentication failed");
+ case EMP_SKYPE_LOGOUTREASON_P2P_CONNECT_FAILED:
+ return _("Peer-to-peer connection failed");
+ case EMP_SKYPE_LOGOUTREASON_SERVER_CONNECT_FAILED:
+ return _("Server connection failed");
+ case EMP_SKYPE_LOGOUTREASON_SERVER_OVERLOADED:
+ return _("Server overloaded");
+ case EMP_SKYPE_LOGOUTREASON_DB_IN_USE:
+ return _("Local database in use");
+ case EMP_SKYPE_LOGOUTREASON_INVALID_SKYPENAME:
+ return _("Invalid username");
+ case EMP_SKYPE_LOGOUTREASON_INVALID_EMAIL:
+ return _("Invalid email address");
+ case EMP_SKYPE_LOGOUTREASON_UNACCEPTABLE_PASSWORD:
+ return _("Unacceptable password");
+ case EMP_SKYPE_LOGOUTREASON_SKYPENAME_TAKEN:
+ return _("Username already taken");
+ case EMP_SKYPE_LOGOUTREASON_REJECTED_AS_UNDERAGE:
+ return _("Rejected as underage");
+ case EMP_SKYPE_LOGOUTREASON_NO_SUCH_IDENTITY:
+ return _("No such identity");
+ case EMP_SKYPE_LOGOUTREASON_INCORRECT_PASSWORD:
+ return _("Incorrect password");
+ case EMP_SKYPE_LOGOUTREASON_TOO_MANY_LOGIN_ATTEMPTS:
+ return _("Too many login attempts");
+ case EMP_SKYPE_LOGOUTREASON_PASSWORD_HAS_CHANGED:
+ return _("Password has changed");
+ case EMP_SKYPE_LOGOUTREASON_PERIODIC_UIC_UPDATE_FAILED:
+ /* FIXME: what now? */
+ return _("Periodic UIC update failed");
+ case EMP_SKYPE_LOGOUTREASON_DB_DISK_FULL:
+ return _("Cannot write to local database: disk full");
+ case EMP_SKYPE_LOGOUTREASON_DB_IO_ERROR:
+ return _("Cannot write to local database: input/output error");
+ case EMP_SKYPE_LOGOUTREASON_DB_CORRUPT:
+ return _("Local database corrupt");
+ case EMP_SKYPE_LOGOUTREASON_DB_FAILURE:
+ return _("Local database failure");
+ case EMP_SKYPE_LOGOUTREASON_INVALID_APP_ID:
+ return _("Invalid application ID");
+ case EMP_SKYPE_LOGOUTREASON_APP_ID_BLACKLISTED:
+ return _("Application ID blacklisted");
+ case EMP_SKYPE_LOGOUTREASON_UNSUPPORTED_VERSION:
+ return _("Unsupported Skype version (software upgrade required)");
+ }
+
+ g_return_val_if_reached (NULL);
+}
diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h
index 7ec96be13..f78007aeb 100644
--- a/libempathy/empathy-utils.h
+++ b/libempathy/empathy-utils.h
@@ -104,6 +104,37 @@ gchar * empathy_get_x509_certificate_hostname (gnutls_x509_crt_t cert);
gchar *empathy_format_currency (gint amount, guint scale, const gchar *currency);
+/* this enum is taken from SkypeKit */
+enum {
+ EMP_SKYPE_LOGOUTREASON_NONE = 0, /* No reason given */
+ EMP_SKYPE_LOGOUTREASON_LOGOUT_CALLED = 1, /* manual logout (or unknown reason from previous session) */
+ EMP_SKYPE_LOGOUTREASON_HTTPS_PROXY_AUTH_FAILED = 2, /* sync errors at login/registration */
+ EMP_SKYPE_LOGOUTREASON_SOCKS_PROXY_AUTH_FAILED = 3, /* sync errors at login/registration */
+ EMP_SKYPE_LOGOUTREASON_P2P_CONNECT_FAILED = 4, /* sync errors at login/registration */
+ EMP_SKYPE_LOGOUTREASON_SERVER_CONNECT_FAILED = 5, /* sync errors at login/registration */
+ EMP_SKYPE_LOGOUTREASON_SERVER_OVERLOADED = 6, /* sync errors at login/registration */
+ EMP_SKYPE_LOGOUTREASON_DB_IN_USE = 7, /* sync errors at login/registration */
+ EMP_SKYPE_LOGOUTREASON_INVALID_SKYPENAME = 8, /* sync errors at registration */
+ EMP_SKYPE_LOGOUTREASON_INVALID_EMAIL = 9, /* sync errors at registration */
+ EMP_SKYPE_LOGOUTREASON_UNACCEPTABLE_PASSWORD = 10, /* sync errors at registration */
+ EMP_SKYPE_LOGOUTREASON_SKYPENAME_TAKEN = 11, /* sync errors at registration */
+ EMP_SKYPE_LOGOUTREASON_REJECTED_AS_UNDERAGE = 12, /* sync errors at registration */
+ EMP_SKYPE_LOGOUTREASON_NO_SUCH_IDENTITY = 13, /* sync errors at login */
+ EMP_SKYPE_LOGOUTREASON_INCORRECT_PASSWORD = 14, /* sync errors at login */
+ EMP_SKYPE_LOGOUTREASON_TOO_MANY_LOGIN_ATTEMPTS = 15, /* sync errors at login */
+ EMP_SKYPE_LOGOUTREASON_PASSWORD_HAS_CHANGED = 16, /* async errors (can happen anytime while logged in) */
+ EMP_SKYPE_LOGOUTREASON_PERIODIC_UIC_UPDATE_FAILED = 17, /* async errors (can happen anytime while logged in) */
+ EMP_SKYPE_LOGOUTREASON_DB_DISK_FULL = 18, /* async errors (can happen anytime while logged in) */
+ EMP_SKYPE_LOGOUTREASON_DB_IO_ERROR = 19, /* async errors (can happen anytime while logged in) */
+ EMP_SKYPE_LOGOUTREASON_DB_CORRUPT = 20, /* async errors (can happen anytime while logged in) */
+ EMP_SKYPE_LOGOUTREASON_DB_FAILURE = 21, /* deprecated (superceded by more detailed DB_* errors) */
+ EMP_SKYPE_LOGOUTREASON_INVALID_APP_ID = 22, /* platform sdk */
+ EMP_SKYPE_LOGOUTREASON_APP_ID_BLACKLISTED = 23, /* platform sdk */
+ EMP_SKYPE_LOGOUTREASON_UNSUPPORTED_VERSION = 24, /* forced upgrade/discontinuation */
+};
+
+const gchar *empathy_skype_reason_to_string (guint skype_reason);
+
G_END_DECLS
#endif /* __EMPATHY_UTILS_H__ */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a137605e5..3145f1965 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,6 +6,7 @@ data/org.gnome.Empathy.gschema.xml.in
data/empathy-accounts.desktop.in.in
libempathy/empathy-ft-handler.c
+libempathy/empathy-message.c
libempathy/empathy-tp-contact-list.c
libempathy/empathy-tp-file.c
libempathy/empathy-utils.c
diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c
index 4c1c788ed..2fcc31e02 100644
--- a/src/empathy-main-window.c
+++ b/src/empathy-main-window.c
@@ -924,15 +924,13 @@ static void
main_window_balance_activate_cb (GtkAction *action,
EmpathyMainWindow *window)
{
- TpAccount *account = g_object_get_data (G_OBJECT (action), "account");
- const char *protocol = tp_account_get_protocol (account);
-
- /* FIXME: need a generic way to find out how to top-up an
- * account that also works with arbitrary SIP and XMPP gateways --
- * https://bugs.freedesktop.org/show_bug.cgi?id=36254 */
- if (!tp_strdiff (protocol, "skype")) {
- empathy_url_show (GTK_WIDGET (window),
- "http://go.skype.com/store.buy.skypecredit");
+ const char *uri;
+
+ uri = g_object_get_data (G_OBJECT (action), "manage-credit-uri");
+
+ if (!tp_str_empty (uri)) {
+ DEBUG ("Top-up credit URI: %s", uri);
+ empathy_url_show (GTK_WIDGET (window), uri);
} else {
DEBUG ("unknown protocol for top-up");
}
@@ -974,23 +972,30 @@ main_window_balance_update_balance (GtkAction *action,
}
static void
-main_window_setup_balance_got_balance (TpProxy *conn,
- const GValue *value,
- const GError *in_error,
- gpointer user_data,
- GObject *action)
+main_window_setup_balance_got_balance_props (TpProxy *conn,
+ GHashTable *props,
+ const GError *in_error,
+ gpointer user_data,
+ GObject *action)
{
GValueArray *balance = NULL;
+ const char *uri;
if (in_error != NULL) {
- DEBUG ("Failed to get account balance: %s",
+ DEBUG ("Failed to get account balance properties: %s",
in_error->message);
- } else if (!G_VALUE_HOLDS (value, TP_STRUCT_TYPE_CURRENCY_AMOUNT)) {
- DEBUG ("Type mismatch");
- } else {
- balance = g_value_get_boxed (value);
+ goto finally;
}
+ balance = tp_asv_get_boxed (props, "AccountBalance",
+ TP_STRUCT_TYPE_CURRENCY_AMOUNT);
+ uri = tp_asv_get_string (props, "ManageCreditURI");
+
+ g_object_set_data_full (action, "manage-credit-uri",
+ g_strdup (uri), g_free);
+ gtk_action_set_sensitive (GTK_ACTION (action), !tp_str_empty (uri));
+
+finally:
main_window_balance_update_balance (GTK_ACTION (action), balance);
}
@@ -1149,10 +1154,9 @@ main_window_setup_balance_conn_ready (GObject *conn,
widget = main_window_setup_balance_create_widget (window, action);
/* request the current balance and monitor for any changes */
- tp_cli_dbus_properties_call_get (conn, -1,
+ tp_cli_dbus_properties_call_get_all (conn, -1,
TP_IFACE_CONNECTION_INTERFACE_BALANCE,
- "AccountBalance",
- main_window_setup_balance_got_balance,
+ main_window_setup_balance_got_balance_props,
window, NULL, G_OBJECT (action));
tp_cli_connection_interface_balance_connect_to_balance_changed (