2 * Copyright (C) 2006-2007 Imendio AB
3 * Copyright (C) 2007-2011 Collabora Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Martyn Russell <martyn@imendio.com>
21 * Xavier Claessens <xclaesse@gmail.com>
22 * Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
30 #include <glib/gi18n-lib.h>
33 #include <telepathy-glib/telepathy-glib.h>
34 #include <telepathy-glib/proxy-subclass.h>
36 #include <telepathy-logger/telepathy-logger.h>
38 # include <telepathy-logger/call-event.h>
41 #include <extensions/extensions.h>
43 #include <libempathy/action-chain-internal.h>
44 #include <libempathy/empathy-chatroom-manager.h>
45 #include <libempathy/empathy-chatroom.h>
46 #include <libempathy/empathy-message.h>
47 #include <libempathy/empathy-request-util.h>
48 #include <libempathy/empathy-utils.h>
49 #include <libempathy/empathy-time.h>
51 #include "empathy-log-window.h"
52 #include "empathy-account-chooser.h"
53 #include "empathy-call-utils.h"
54 #include "empathy-chat-view.h"
55 #include "empathy-contact-dialogs.h"
56 #include "empathy-images.h"
57 #include "empathy-theme-manager.h"
58 #include "empathy-ui-utils.h"
60 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
61 #include <libempathy/empathy-debug.h>
67 GtkWidget *button_profile;
68 GtkWidget *button_chat;
69 GtkWidget *button_call;
70 GtkWidget *button_video;
72 GtkWidget *search_entry;
77 GtkWidget *treeview_who;
78 GtkWidget *treeview_what;
79 GtkWidget *treeview_when;
80 GtkWidget *treeview_events;
82 GtkTreeStore *store_events;
84 GtkWidget *account_chooser;
88 TplActionChain *chain;
89 TplLogManager *log_manager;
91 /* Used to cancel logger calls when no longer needed */
94 /* List of owned TplLogSearchHits, free with tpl_log_search_hit_free */
98 /* Only used while waiting for the account chooser to be ready */
99 TpAccount *selected_account;
100 gchar *selected_chat_id;
101 gboolean selected_is_chatroom;
104 static void log_window_destroy_cb (GtkWidget *widget,
105 EmpathyLogWindow *window);
106 static void log_window_search_entry_changed_cb (GtkWidget *entry,
107 EmpathyLogWindow *window);
108 static void log_window_search_entry_activate_cb (GtkWidget *widget,
109 EmpathyLogWindow *window);
110 static void log_window_search_entry_icon_pressed_cb (GtkEntry *entry,
111 GtkEntryIconPosition icon_pos,
114 static void log_window_who_populate (EmpathyLogWindow *window);
115 static void log_window_who_setup (EmpathyLogWindow *window);
116 static void log_window_when_setup (EmpathyLogWindow *window);
117 static void log_window_what_setup (EmpathyLogWindow *window);
118 static void log_window_events_setup (EmpathyLogWindow *window);
119 static void log_window_chats_accounts_changed_cb (GtkWidget *combobox,
120 EmpathyLogWindow *window);
121 static void log_window_chats_set_selected (EmpathyLogWindow *window);
122 static void log_window_chats_get_messages (EmpathyLogWindow *window,
123 gboolean force_get_dates);
124 static void log_window_when_changed_cb (GtkTreeSelection *selection,
125 EmpathyLogWindow *window);
126 static void log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
127 EmpathyLogWindow *window);
130 empathy_account_chooser_filter_has_logs (TpAccount *account,
131 EmpathyAccountChooserFilterResultCallback callback,
132 gpointer callback_data,
180 COL_EVENTS_PRETTY_DATE,
189 #define CALENDAR_ICON "stock_calendar"
191 /* Seconds between two messages to be considered one conversation */
192 #define MAX_GAP 30*60
194 #define WHAT_TYPE_SEPARATOR -1
198 EVENT_CALL_INCOMING = 1 << 0,
199 EVENT_CALL_OUTGOING = 1 << 1,
200 EVENT_CALL_MISSED = 1 << 2,
201 EVENT_CALL_ALL = 1 << 3,
204 static EmpathyLogWindow *log_window = NULL;
206 static gboolean has_element;
209 #define _date_copy(d) g_date_new_julian (g_date_get_julian (d))
214 EmpathyLogWindow *window;
218 TplEventTypeMask event_mask;
219 EventSubtype subtype;
224 ctx_new (EmpathyLogWindow *window,
228 TplEventTypeMask event_mask,
229 EventSubtype subtype,
232 Ctx *ctx = g_slice_new0 (Ctx);
234 ctx->window = window;
236 ctx->account = g_object_ref (account);
238 ctx->entity = g_object_ref (entity);
240 ctx->date = _date_copy (date);
241 ctx->event_mask = event_mask;
242 ctx->subtype = subtype;
251 tp_clear_object (&ctx->account);
252 tp_clear_object (&ctx->entity);
253 tp_clear_pointer (&ctx->date, g_date_free);
255 g_slice_free (Ctx, ctx);
259 account_chooser_ready_cb (EmpathyAccountChooser *chooser,
260 EmpathyLogWindow *window)
262 /* We'll display the account once the model has been populate with the chats
263 * of this account. */
264 empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (
265 window->account_chooser), window->selected_account);
269 select_account_once_ready (EmpathyLogWindow *self,
271 const gchar *chat_id,
272 gboolean is_chatroom)
274 EmpathyAccountChooser *account_chooser;
276 account_chooser = EMPATHY_ACCOUNT_CHOOSER (self->account_chooser);
278 tp_clear_object (&self->selected_account);
279 self->selected_account = g_object_ref (account);
281 g_free (self->selected_chat_id);
282 self->selected_chat_id = g_strdup (chat_id);
284 self->selected_is_chatroom = is_chatroom;
286 if (empathy_account_chooser_is_ready (account_chooser))
287 account_chooser_ready_cb (account_chooser, self);
289 /* Chat will be selected once the account chooser is ready */
290 g_signal_connect (account_chooser, "ready",
291 G_CALLBACK (account_chooser_ready_cb), self);
295 toolbutton_profile_clicked (GtkToolButton *toolbutton,
296 EmpathyLogWindow *window)
299 GtkTreeSelection *selection;
306 EmpathyContact *contact;
309 g_return_if_fail (window != NULL);
311 view = GTK_TREE_VIEW (log_window->treeview_who);
312 selection = gtk_tree_view_get_selection (view);
314 paths = gtk_tree_selection_get_selected_rows (selection, &model);
315 g_return_if_fail (paths != NULL);
318 gtk_tree_model_get_iter (model, &iter, path);
319 gtk_tree_model_get (model, &iter,
320 COL_WHO_ACCOUNT, &account,
321 COL_WHO_TARGET, &target,
325 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
327 g_return_if_fail (type == COL_TYPE_NORMAL);
329 contact = empathy_contact_from_tpl_contact (account, target);
330 empathy_contact_information_dialog_show (contact,
331 GTK_WINDOW (window->window));
332 g_object_unref (contact);
334 g_object_unref (account);
335 g_object_unref (target);
339 toolbutton_chat_clicked (GtkToolButton *toolbutton,
340 EmpathyLogWindow *window)
343 GtkTreeSelection *selection;
350 EmpathyContact *contact;
353 g_return_if_fail (window != NULL);
355 view = GTK_TREE_VIEW (log_window->treeview_who);
356 selection = gtk_tree_view_get_selection (view);
358 paths = gtk_tree_selection_get_selected_rows (selection, &model);
359 g_return_if_fail (paths != NULL);
362 gtk_tree_model_get_iter (model, &iter, path);
363 gtk_tree_model_get (model, &iter,
364 COL_WHO_ACCOUNT, &account,
365 COL_WHO_TARGET, &target,
369 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
371 g_return_if_fail (type == COL_TYPE_NORMAL);
373 contact = empathy_contact_from_tpl_contact (account, target);
374 empathy_chat_with_contact (contact,
375 gtk_get_current_event_time ());
377 g_object_unref (contact);
378 g_object_unref (account);
379 g_object_unref (target);
383 toolbutton_av_clicked (GtkToolButton *toolbutton,
384 EmpathyLogWindow *window)
387 GtkTreeSelection *selection;
397 g_return_if_fail (window != NULL);
399 view = GTK_TREE_VIEW (log_window->treeview_who);
400 selection = gtk_tree_view_get_selection (view);
402 paths = gtk_tree_selection_get_selected_rows (selection, &model);
403 g_return_if_fail (paths != NULL);
406 gtk_tree_model_get_iter (model, &iter, path);
407 gtk_tree_model_get (model, &iter,
408 COL_WHO_ACCOUNT, &account,
409 COL_WHO_NAME, &contact,
413 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
415 g_return_if_fail (type == COL_TYPE_NORMAL);
417 video = (GTK_WIDGET (toolbutton) == window->button_video);
419 empathy_call_new_with_streams (contact, account,
420 TRUE, video, gtk_get_current_event_time ());
423 g_object_unref (account);
427 empathy_log_window_show (TpAccount *account,
428 const gchar *chat_id,
429 gboolean is_chatroom,
432 EmpathyAccountChooser *account_chooser;
435 EmpathyLogWindow *window;
436 GtkWidget *vbox, *accounts, *search, *label, *quit;
438 if (log_window != NULL)
440 gtk_window_present (GTK_WINDOW (log_window->window));
442 if (account != NULL && chat_id != NULL)
443 select_account_once_ready (log_window, account, chat_id, is_chatroom);
445 return log_window->window;
448 log_window = g_new0 (EmpathyLogWindow, 1);
449 log_window->chain = _tpl_action_chain_new_async (NULL, NULL, NULL);
451 log_window->log_manager = tpl_log_manager_dup_singleton ();
455 filename = empathy_file_lookup ("empathy-log-window.ui", "libempathy-gtk");
456 gui = empathy_builder_get_file (filename,
457 "log_window", &window->window,
458 "toolbutton_profile", &window->button_profile,
459 "toolbutton_chat", &window->button_chat,
460 "toolbutton_call", &window->button_call,
461 "toolbutton_video", &window->button_video,
462 "toolbutton_accounts", &accounts,
463 "toolbutton_search", &search,
464 "imagemenuitem_quit", &quit,
465 "treeview_who", &window->treeview_who,
466 "treeview_what", &window->treeview_what,
467 "treeview_when", &window->treeview_when,
468 "treeview_events", &window->treeview_events,
469 "notebook", &window->notebook,
470 "spinner", &window->spinner,
474 empathy_builder_connect (gui, window,
475 "log_window", "destroy", log_window_destroy_cb,
476 "toolbutton_profile", "clicked", toolbutton_profile_clicked,
477 "toolbutton_chat", "clicked", toolbutton_chat_clicked,
478 "toolbutton_call", "clicked", toolbutton_av_clicked,
479 "toolbutton_video", "clicked", toolbutton_av_clicked,
480 "imagemenuitem_delete", "activate", log_window_delete_menu_clicked_cb,
483 g_object_unref (gui);
485 g_object_add_weak_pointer (G_OBJECT (window->window),
486 (gpointer) &log_window);
488 g_signal_connect_swapped (quit, "activate",
489 G_CALLBACK (gtk_widget_destroy), window->window);
491 /* Account chooser for chats */
492 vbox = gtk_vbox_new (FALSE, 3);
494 window->account_chooser = empathy_account_chooser_new ();
495 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
496 empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
497 empathy_account_chooser_set_filter (account_chooser,
498 empathy_account_chooser_filter_has_logs, NULL);
499 empathy_account_chooser_set_all (account_chooser);
501 g_signal_connect (window->account_chooser, "changed",
502 G_CALLBACK (log_window_chats_accounts_changed_cb),
505 label = gtk_label_new (_("Show"));
507 gtk_box_pack_start (GTK_BOX (vbox),
508 window->account_chooser,
511 gtk_box_pack_start (GTK_BOX (vbox),
515 gtk_widget_show_all (vbox);
516 gtk_container_add (GTK_CONTAINER (accounts), vbox);
519 vbox = gtk_vbox_new (FALSE, 3);
521 window->search_entry = gtk_entry_new ();
522 gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
523 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_FIND);
524 gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
525 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
527 label = gtk_label_new (_("Search"));
529 gtk_box_pack_start (GTK_BOX (vbox),
530 window->search_entry,
533 gtk_box_pack_start (GTK_BOX (vbox),
537 gtk_widget_show_all (vbox);
538 gtk_container_add (GTK_CONTAINER (search), vbox);
540 g_signal_connect (window->search_entry, "changed",
541 G_CALLBACK (log_window_search_entry_changed_cb),
544 g_signal_connect (window->search_entry, "activate",
545 G_CALLBACK (log_window_search_entry_activate_cb),
548 g_signal_connect (window->search_entry, "icon-press",
549 G_CALLBACK (log_window_search_entry_icon_pressed_cb),
553 log_window_events_setup (window);
554 log_window_who_setup (window);
555 log_window_what_setup (window);
556 log_window_when_setup (window);
558 log_window_who_populate (window);
560 if (account != NULL && chat_id != NULL)
561 select_account_once_ready (window, account, chat_id, is_chatroom);
564 gtk_window_set_transient_for (GTK_WINDOW (window->window),
565 GTK_WINDOW (parent));
567 gtk_widget_show (window->window);
569 return window->window;
573 log_window_destroy_cb (GtkWidget *widget,
574 EmpathyLogWindow *window)
576 if (window->source != 0)
577 g_source_remove (window->source);
579 g_free (window->last_find);
580 _tpl_action_chain_free (window->chain);
581 g_object_unref (window->log_manager);
582 tp_clear_object (&window->selected_account);
583 g_free (window->selected_chat_id);
589 account_equal (TpAccount *a,
592 return g_str_equal (tp_proxy_get_object_path (a),
593 tp_proxy_get_object_path (b));
597 entity_equal (TplEntity *a,
600 return g_str_equal (tpl_entity_get_identifier (a),
601 tpl_entity_get_identifier (b));
605 is_same_confroom (TplEvent *e1,
608 TplEntity *sender1 = tpl_event_get_sender (e1);
609 TplEntity *receiver1 = tpl_event_get_receiver (e1);
610 TplEntity *sender2 = tpl_event_get_sender (e2);
611 TplEntity *receiver2 = tpl_event_get_receiver (e2);
612 TplEntity *room1, *room2;
614 if (receiver1 == NULL || receiver2 == NULL)
617 if (tpl_entity_get_entity_type (sender1) == TPL_ENTITY_ROOM)
619 else if (tpl_entity_get_entity_type (receiver1) == TPL_ENTITY_ROOM)
624 if (tpl_entity_get_entity_type (sender2) == TPL_ENTITY_ROOM)
626 else if (tpl_entity_get_entity_type (receiver2) == TPL_ENTITY_ROOM)
631 return g_str_equal (tpl_entity_get_identifier (room1),
632 tpl_entity_get_identifier (room2));
636 event_get_target (TplEvent *event)
638 TplEntity *sender = tpl_event_get_sender (event);
639 TplEntity *receiver = tpl_event_get_receiver (event);
641 if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
648 model_is_parent (GtkTreeModel *model,
652 TplEvent *stored_event;
655 gboolean found = FALSE;
658 if (gtk_tree_model_iter_parent (model, &parent, iter))
661 gtk_tree_model_get (model, iter,
662 COL_EVENTS_ACCOUNT, &account,
663 COL_EVENTS_TARGET, &target,
664 COL_EVENTS_EVENT, &stored_event,
667 if (G_OBJECT_TYPE (event) == G_OBJECT_TYPE (stored_event) &&
668 account_equal (account, tpl_event_get_account (event)) &&
669 (entity_equal (target, event_get_target (event)) ||
670 is_same_confroom (event, stored_event)))
675 gtk_tree_model_iter_nth_child (model, &child, iter,
676 gtk_tree_model_iter_n_children (model, iter) - 1);
678 gtk_tree_model_get (model, &child,
679 COL_EVENTS_TS, ×tamp,
682 if (ABS (tpl_event_get_timestamp (event) - timestamp) < MAX_GAP)
684 /* The gap is smaller than 30 min */
689 g_object_unref (stored_event);
690 g_object_unref (account);
691 g_object_unref (target);
697 get_contact_alias_for_message (EmpathyMessage *message)
699 EmpathyContact *sender, *receiver;
701 sender = empathy_message_get_sender (message);
702 receiver = empathy_message_get_receiver (message);
704 if (empathy_contact_is_user (sender))
705 return empathy_contact_get_alias (receiver);
707 return empathy_contact_get_alias (sender);
711 get_parent_iter_for_message (TplEvent *event,
712 EmpathyMessage *message,
718 gboolean parent_found = FALSE;
721 store = log_window->store_events;
722 model = GTK_TREE_MODEL (store);
724 for (next = gtk_tree_model_get_iter_first (model, &iter);
726 next = gtk_tree_model_iter_next (model, &iter))
728 if ((parent_found = model_is_parent (model, &iter, event)))
739 gchar *body, *pretty_date;
741 date = g_date_time_new_from_unix_utc (
742 tpl_event_get_timestamp (event));
744 pretty_date = g_date_time_format (date,
745 C_("A date with the time", "%A, %e %B %Y %X"));
747 body = g_markup_printf_escaped (_("Chat with %s"),
748 get_contact_alias_for_message (message));
750 gtk_tree_store_append (store, &iter, NULL);
751 gtk_tree_store_set (store, &iter,
752 COL_EVENTS_TS, tpl_event_get_timestamp (event),
753 COL_EVENTS_PRETTY_DATE, pretty_date,
754 COL_EVENTS_TEXT, body,
755 COL_EVENTS_ICON, "stock_text_justify",
756 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
757 COL_EVENTS_TARGET, event_get_target (event),
758 COL_EVENTS_EVENT, event,
764 g_free (pretty_date);
765 g_date_time_unref (date);
770 get_icon_for_event (TplEvent *event)
772 const gchar *icon = NULL;
774 if (TPL_IS_TEXT_EVENT (event))
776 TplTextEvent *text = TPL_TEXT_EVENT (event);
778 if (!tp_str_empty (tpl_text_event_get_supersedes_token (text)))
779 icon = EMPATHY_IMAGE_EDIT_MESSAGE;
781 #ifdef HAVE_CALL_LOGS
782 else if (TPL_IS_CALL_EVENT (event))
784 TplCallEvent *call = TPL_CALL_EVENT (event);
785 TplCallEndReason reason = tpl_call_event_get_end_reason (call);
786 TplEntity *sender = tpl_event_get_sender (event);
787 TplEntity *receiver = tpl_event_get_receiver (event);
789 if (reason == TPL_CALL_END_REASON_NO_ANSWER)
790 icon = EMPATHY_IMAGE_CALL_MISSED;
791 else if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
792 icon = EMPATHY_IMAGE_CALL_OUTGOING;
793 else if (tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
794 icon = EMPATHY_IMAGE_CALL_INCOMING;
802 log_window_append_chat_message (TplEvent *event,
803 EmpathyMessage *message)
805 GtkTreeStore *store = log_window->store_events;
806 GtkTreeIter iter, parent;
807 gchar *pretty_date, *body;
810 date = g_date_time_new_from_unix_utc (
811 tpl_event_get_timestamp (event));
813 pretty_date = g_date_time_format (date, "%X");
815 get_parent_iter_for_message (event, message, &parent);
817 if (tpl_text_event_get_message_type (TPL_TEXT_EVENT (event))
818 == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION)
820 /* Translators: this is an emote: '* Danielle waves' */
821 body = g_markup_printf_escaped (_("<i>* %s %s</i>"),
822 tpl_entity_get_alias (tpl_event_get_sender (event)),
823 empathy_message_get_body (message));
827 /* Translators: this is a message: 'Danielle: hello'
828 * The string in bold is the sender's name */
829 body = g_markup_printf_escaped (_("<b>%s:</b> %s"),
830 tpl_entity_get_alias (tpl_event_get_sender (event)),
831 empathy_message_get_body (message));
834 gtk_tree_store_append (store, &iter, &parent);
835 gtk_tree_store_set (store, &iter,
836 COL_EVENTS_TS, tpl_event_get_timestamp (event),
837 COL_EVENTS_PRETTY_DATE, pretty_date,
838 COL_EVENTS_TEXT, body,
839 COL_EVENTS_ICON, get_icon_for_event (event),
840 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
841 COL_EVENTS_TARGET, event_get_target (event),
842 COL_EVENTS_EVENT, event,
846 g_free (pretty_date);
847 g_date_time_unref (date);
850 #ifdef HAVE_CALL_LOGS
852 log_window_append_call (TplEvent *event,
853 EmpathyMessage *message)
855 TplCallEvent *call = TPL_CALL_EVENT (event);
856 GtkTreeStore *store = log_window->store_events;
857 GtkTreeIter iter, child;
858 gchar *pretty_date, *duration, *finished;
859 GDateTime *started_date, *finished_date;
862 started_date = g_date_time_new_from_unix_utc (
863 tpl_event_get_timestamp (event));
865 pretty_date = g_date_time_format (started_date,
866 C_("A date with the time", "%A, %e %B %Y %X"));
868 gtk_tree_store_append (store, &iter, NULL);
869 gtk_tree_store_set (store, &iter,
870 COL_EVENTS_TS, tpl_event_get_timestamp (event),
871 COL_EVENTS_PRETTY_DATE, pretty_date,
872 COL_EVENTS_TEXT, empathy_message_get_body (message),
873 COL_EVENTS_ICON, get_icon_for_event (event),
874 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
875 COL_EVENTS_TARGET, event_get_target (event),
876 COL_EVENTS_EVENT, event,
879 if (tpl_call_event_get_end_reason (call) != TPL_CALL_END_REASON_NO_ANSWER)
883 span = tpl_call_event_get_duration (TPL_CALL_EVENT (event));
885 duration = g_strdup_printf (_("%" G_GINT64_FORMAT " seconds"), span);
887 duration = g_strdup_printf (_("%" G_GINT64_FORMAT " minutes"),
890 finished_date = g_date_time_add (started_date, -span);
891 finished = g_date_time_format (finished_date, "%X");
892 g_date_time_unref (finished_date);
894 body = g_strdup_printf (_("Call took %s, ended at %s"),
900 gtk_tree_store_append (store, &child, &iter);
901 gtk_tree_store_set (store, &child,
902 COL_EVENTS_TS, tpl_event_get_timestamp (event),
903 COL_EVENTS_TEXT, body,
904 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
905 COL_EVENTS_TARGET, event_get_target (event),
906 COL_EVENTS_EVENT, event,
912 g_free (pretty_date);
913 g_date_time_unref (started_date);
918 log_window_append_message (TplEvent *event,
919 EmpathyMessage *message)
921 if (TPL_IS_TEXT_EVENT (event))
922 log_window_append_chat_message (event, message);
923 #ifdef HAVE_CALL_LOGS
924 else if (TPL_IS_CALL_EVENT (event))
925 log_window_append_call (event, message);
928 DEBUG ("Message type not handled");
932 add_all_accounts_and_entities (GList **accounts,
939 view = GTK_TREE_VIEW (log_window->treeview_who);
940 model = gtk_tree_view_get_model (view);
942 if (!gtk_tree_model_get_iter_first (model, &iter))
951 gtk_tree_model_get (model, &iter,
952 COL_WHO_ACCOUNT, &account,
953 COL_WHO_TARGET, &entity,
957 if (type != COL_TYPE_NORMAL)
960 if (accounts != NULL)
961 *accounts = g_list_append (*accounts, account);
963 if (entities != NULL)
964 *entities = g_list_append (*entities, entity);
966 while (gtk_tree_model_iter_next (model, &iter));
970 log_window_get_selected (EmpathyLogWindow *window,
974 TplEventTypeMask *event_mask,
975 EventSubtype *subtype)
979 GtkTreeSelection *selection;
981 TplEventTypeMask ev = 0;
986 view = GTK_TREE_VIEW (window->treeview_who);
987 model = gtk_tree_view_get_model (view);
988 selection = gtk_tree_view_get_selection (view);
990 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
994 if (accounts != NULL)
996 if (entities != NULL)
999 for (l = paths; l != NULL; l = l->next)
1001 GtkTreePath *path = l->data;
1005 gtk_tree_model_get_iter (model, &iter, path);
1006 gtk_tree_model_get (model, &iter,
1007 COL_WHO_ACCOUNT, &account,
1008 COL_WHO_TARGET, &entity,
1009 COL_WHO_TYPE, &type,
1012 if (type == COL_TYPE_ANY)
1014 if (accounts != NULL || entities != NULL)
1015 add_all_accounts_and_entities (accounts, entities);
1019 if (accounts != NULL)
1020 *accounts = g_list_append (*accounts, g_object_ref (account));
1022 if (entities != NULL)
1023 *entities = g_list_append (*entities, g_object_ref (entity));
1025 g_object_unref (account);
1026 g_object_unref (entity);
1028 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1030 view = GTK_TREE_VIEW (window->treeview_what);
1031 model = gtk_tree_view_get_model (view);
1032 selection = gtk_tree_view_get_selection (view);
1034 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1035 for (l = paths; l != NULL; l = l->next)
1037 GtkTreePath *path = l->data;
1038 TplEventTypeMask mask;
1039 EventSubtype submask;
1041 gtk_tree_model_get_iter (model, &iter, path);
1042 gtk_tree_model_get (model, &iter,
1043 COL_WHAT_TYPE, &mask,
1044 COL_WHAT_SUBTYPE, &submask,
1050 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1052 view = GTK_TREE_VIEW (window->treeview_when);
1053 model = gtk_tree_view_get_model (view);
1054 selection = gtk_tree_view_get_selection (view);
1060 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1061 for (l = paths; l != NULL; l = l->next)
1063 GtkTreePath *path = l->data;
1066 gtk_tree_model_get_iter (model, &iter, path);
1067 gtk_tree_model_get (model, &iter,
1068 COL_WHEN_DATE, &date,
1071 *dates = g_list_append (*dates, date);
1073 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1076 if (event_mask != NULL)
1079 if (subtype != NULL)
1086 model_has_entity (GtkTreeModel *model,
1091 TplLogSearchHit *hit = data;
1094 gboolean ret = FALSE;
1096 gtk_tree_model_get (model, iter,
1098 COL_WHO_ACCOUNT, &a,
1101 if (e != NULL && entity_equal (hit->target, e) &&
1102 a != NULL && account_equal (hit->account, a))
1104 ret = has_element = TRUE;
1107 tp_clear_object (&e);
1108 tp_clear_object (&a);
1114 model_has_date (GtkTreeModel *model,
1122 gtk_tree_model_get (model, iter,
1126 if (!g_date_compare (date, d))
1136 get_events_for_date (TplActionChain *chain, gpointer user_data);
1139 populate_events_from_search_hits (GList *accounts,
1143 TplEventTypeMask event_mask;
1144 EventSubtype subtype;
1147 gboolean is_anytime = FALSE;
1149 if (!log_window_get_selected (log_window,
1150 NULL, NULL, NULL, &event_mask, &subtype))
1153 anytime = g_date_new_dmy (2, 1, -1);
1154 if (g_list_find_custom (dates, anytime, (GCompareFunc) g_date_compare))
1157 for (l = log_window->hits; l != NULL; l = l->next)
1159 TplLogSearchHit *hit = l->data;
1161 gboolean found = FALSE;
1163 /* Protect against invalid data (corrupt or old log files). */
1164 if (hit->account == NULL || hit->target == NULL)
1167 for (acc = accounts, targ = targets;
1168 acc != NULL && targ != NULL && !found;
1169 acc = acc->next, targ = targ->next)
1171 TpAccount *account = acc->data;
1172 TplEntity *target = targ->data;
1174 if (account_equal (hit->account, account) &&
1175 entity_equal (hit->target, target))
1183 g_list_find_custom (dates, hit->date, (GCompareFunc) g_date_compare)
1188 ctx = ctx_new (log_window, hit->account, hit->target, hit->date,
1189 event_mask, subtype, log_window->count);
1190 _tpl_action_chain_append (log_window->chain,
1191 get_events_for_date, ctx);
1195 _tpl_action_chain_start (log_window->chain);
1197 g_date_free (anytime);
1201 format_date_for_display (GDate *date)
1207 /* g_date_strftime sucks */
1209 now = g_date_new ();
1210 g_date_set_time_t (now, time (NULL));
1212 days_elapsed = g_date_days_between (date, now);
1214 if (days_elapsed < 0)
1218 else if (days_elapsed == 0)
1220 text = g_strdup (_("Today"));
1222 else if (days_elapsed == 1)
1224 text = g_strdup (_("Yesterday"));
1230 dt = g_date_time_new_utc (g_date_get_year (date),
1231 g_date_get_month (date), g_date_get_day (date),
1234 if (days_elapsed <= 7)
1235 text = g_date_time_format (dt, "%A");
1237 text = g_date_time_format (dt,
1238 C_("A date such as '23 May 2010', "
1239 "%e is the day, %B the month and %Y the year",
1242 g_date_time_unref (dt);
1251 populate_dates_from_search_hits (GList *accounts,
1256 GtkTreeModel *model;
1257 GtkListStore *store;
1258 GtkTreeSelection *selection;
1261 if (log_window == NULL)
1264 view = GTK_TREE_VIEW (log_window->treeview_when);
1265 model = gtk_tree_view_get_model (view);
1266 store = GTK_LIST_STORE (model);
1267 selection = gtk_tree_view_get_selection (view);
1269 for (l = log_window->hits; l != NULL; l = l->next)
1271 TplLogSearchHit *hit = l->data;
1273 gboolean found = FALSE;
1275 /* Protect against invalid data (corrupt or old log files). */
1276 if (hit->account == NULL || hit->target == NULL)
1279 for (acc = accounts, targ = targets;
1280 acc != NULL && targ != NULL && !found;
1281 acc = acc->next, targ = targ->next)
1283 TpAccount *account = acc->data;
1284 TplEntity *target = targ->data;
1286 if (account_equal (hit->account, account) &&
1287 entity_equal (hit->target, target))
1294 /* Add the date if it's not already there */
1295 has_element = FALSE;
1296 gtk_tree_model_foreach (model, model_has_date, hit->date);
1299 gchar *text = format_date_for_display (hit->date);
1301 gtk_list_store_append (store, &iter);
1302 gtk_list_store_set (store, &iter,
1303 COL_WHEN_DATE, hit->date,
1304 COL_WHEN_TEXT, text,
1305 COL_WHEN_ICON, CALENDAR_ICON,
1310 if (gtk_tree_model_get_iter_first (model, &iter))
1312 gtk_list_store_prepend (store, &iter);
1313 gtk_list_store_set (store, &iter,
1314 COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
1315 COL_WHEN_TEXT, "separator",
1318 gtk_list_store_prepend (store, &iter);
1319 gtk_list_store_set (store, &iter,
1320 COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
1321 COL_WHEN_TEXT, _("Anytime"),
1324 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 2))
1325 gtk_tree_selection_select_iter (selection, &iter);
1330 populate_entities_from_search_hits (void)
1332 EmpathyAccountChooser *account_chooser;
1335 GtkTreeModel *model;
1337 GtkListStore *store;
1340 view = GTK_TREE_VIEW (log_window->treeview_who);
1341 model = gtk_tree_view_get_model (view);
1342 store = GTK_LIST_STORE (model);
1344 gtk_list_store_clear (store);
1346 account_chooser = EMPATHY_ACCOUNT_CHOOSER (log_window->account_chooser);
1347 account = empathy_account_chooser_get_account (account_chooser);
1349 for (l = log_window->hits; l; l = l->next)
1351 TplLogSearchHit *hit = l->data;
1353 /* Protect against invalid data (corrupt or old log files). */
1354 if (hit->account == NULL || hit->target == NULL)
1357 /* Filter based on the selected account */
1358 if (account != NULL && !account_equal (account, hit->account))
1361 /* Add the entity if it's not already there */
1362 has_element = FALSE;
1363 gtk_tree_model_foreach (model, model_has_entity, hit);
1366 TplEntityType type = tpl_entity_get_entity_type (hit->target);
1367 gboolean room = type == TPL_ENTITY_ROOM;
1369 gtk_list_store_append (store, &iter);
1370 gtk_list_store_set (store, &iter,
1371 COL_WHO_TYPE, COL_TYPE_NORMAL,
1372 COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
1373 : EMPATHY_IMAGE_AVATAR_DEFAULT,
1374 COL_WHO_NAME, tpl_entity_get_alias (hit->target),
1375 COL_WHO_ACCOUNT, hit->account,
1376 COL_WHO_TARGET, hit->target,
1381 if (gtk_tree_model_get_iter_first (model, &iter))
1383 gtk_list_store_prepend (store, &iter);
1384 gtk_list_store_set (store, &iter,
1385 COL_WHO_TYPE, COL_TYPE_SEPARATOR,
1386 COL_WHO_NAME, "separator",
1389 gtk_list_store_prepend (store, &iter);
1390 gtk_list_store_set (store, &iter,
1391 COL_WHO_TYPE, COL_TYPE_ANY,
1392 COL_WHO_NAME, _("Anyone"),
1396 /* FIXME: select old entity if still available */
1400 log_manager_searched_new_cb (GObject *manager,
1401 GAsyncResult *result,
1406 GtkTreeSelection *selection;
1407 GError *error = NULL;
1409 if (log_window == NULL)
1412 if (!tpl_log_manager_search_finish (TPL_LOG_MANAGER (manager),
1413 result, &hits, &error))
1415 DEBUG ("%s. Aborting", error->message);
1416 g_error_free (error);
1420 tp_clear_pointer (&log_window->hits, tpl_log_manager_search_free);
1421 log_window->hits = hits;
1423 populate_entities_from_search_hits ();
1425 view = GTK_TREE_VIEW (log_window->treeview_when);
1426 selection = gtk_tree_view_get_selection (view);
1428 g_signal_handlers_unblock_by_func (selection,
1429 log_window_when_changed_cb,
1434 log_window_find_populate (EmpathyLogWindow *window,
1435 const gchar *search_criteria)
1438 GtkTreeModel *model;
1439 GtkTreeSelection *selection;
1440 GtkListStore *store;
1442 gtk_tree_store_clear (window->store_events);
1444 view = GTK_TREE_VIEW (window->treeview_who);
1445 model = gtk_tree_view_get_model (view);
1446 store = GTK_LIST_STORE (model);
1448 gtk_list_store_clear (store);
1450 view = GTK_TREE_VIEW (window->treeview_when);
1451 model = gtk_tree_view_get_model (view);
1452 store = GTK_LIST_STORE (model);
1453 selection = gtk_tree_view_get_selection (view);
1455 gtk_list_store_clear (store);
1457 if (EMP_STR_EMPTY (search_criteria))
1459 tp_clear_pointer (&window->hits, tpl_log_manager_search_free);
1460 log_window_who_populate (window);
1464 g_signal_handlers_block_by_func (selection,
1465 log_window_when_changed_cb,
1468 tpl_log_manager_search_async (window->log_manager,
1469 search_criteria, TPL_EVENT_MASK_ANY,
1470 log_manager_searched_new_cb, NULL);
1474 start_find_search (EmpathyLogWindow *window)
1478 str = gtk_entry_get_text (GTK_ENTRY (window->search_entry));
1480 /* Don't find the same crap again */
1481 if (window->last_find && !tp_strdiff (window->last_find, str))
1484 g_free (window->last_find);
1485 window->last_find = g_strdup (str);
1487 log_window_find_populate (window, str);
1493 log_window_search_entry_changed_cb (GtkWidget *entry,
1494 EmpathyLogWindow *window)
1496 if (window->source != 0)
1497 g_source_remove (window->source);
1498 window->source = g_timeout_add (500, (GSourceFunc) start_find_search,
1503 log_window_search_entry_activate_cb (GtkWidget *entry,
1504 EmpathyLogWindow *self)
1506 start_find_search (self);
1510 log_window_search_entry_icon_pressed_cb (GtkEntry *entry,
1511 GtkEntryIconPosition icon_pos,
1515 if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
1518 gtk_entry_buffer_set_text (gtk_entry_get_buffer (entry),
1523 log_window_update_buttons_sensitivity (EmpathyLogWindow *window,
1524 GtkTreeModel *model,
1525 GtkTreeSelection *selection)
1527 EmpathyContact *contact;
1528 EmpathyCapabilities capabilities;
1534 gboolean profile, chat, call, video;
1536 profile = chat = call = video = FALSE;
1538 if (!gtk_tree_model_get_iter_first (model, &iter))
1541 if (gtk_tree_selection_count_selected_rows (selection) != 1)
1544 if (gtk_tree_selection_iter_is_selected (selection, &iter))
1547 paths = gtk_tree_selection_get_selected_rows (selection, &model);
1548 g_return_if_fail (paths != NULL);
1551 gtk_tree_model_get_iter (model, &iter, path);
1552 gtk_tree_model_get (model, &iter,
1553 COL_WHO_ACCOUNT, &account,
1554 COL_WHO_TARGET, &target,
1557 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1559 contact = empathy_contact_from_tpl_contact (account, target);
1561 g_object_unref (account);
1562 g_object_unref (target);
1564 capabilities = empathy_contact_get_capabilities (contact);
1566 profile = chat = TRUE;
1567 call = capabilities & EMPATHY_CAPABILITIES_AUDIO;
1568 video = capabilities & EMPATHY_CAPABILITIES_VIDEO;
1571 gtk_widget_set_sensitive (window->button_profile, profile);
1572 gtk_widget_set_sensitive (window->button_chat, chat);
1573 gtk_widget_set_sensitive (window->button_call, call);
1574 gtk_widget_set_sensitive (window->button_video, video);
1578 log_window_who_changed_cb (GtkTreeSelection *selection,
1579 EmpathyLogWindow *window)
1582 GtkTreeModel *model;
1585 DEBUG ("log_window_who_changed_cb");
1587 view = gtk_tree_selection_get_tree_view (selection);
1588 model = gtk_tree_view_get_model (view);
1590 if (gtk_tree_model_get_iter_first (model, &iter))
1592 /* If 'Anyone' is selected, everything else should be deselected */
1593 if (gtk_tree_selection_iter_is_selected (selection, &iter))
1595 g_signal_handlers_block_by_func (selection,
1596 log_window_who_changed_cb,
1599 gtk_tree_selection_unselect_all (selection);
1600 gtk_tree_selection_select_iter (selection, &iter);
1602 g_signal_handlers_unblock_by_func (selection,
1603 log_window_who_changed_cb,
1608 log_window_update_buttons_sensitivity (window, model, selection);
1610 /* The contact changed, so the dates need to be updated */
1611 log_window_chats_get_messages (window, TRUE);
1615 log_manager_got_entities_cb (GObject *manager,
1616 GAsyncResult *result,
1619 Ctx *ctx = user_data;
1623 GtkTreeModel *model;
1624 GtkTreeSelection *selection;
1625 GtkListStore *store;
1627 GError *error = NULL;
1628 gboolean select_account = FALSE;
1630 if (log_window == NULL)
1633 if (log_window->count != ctx->count)
1636 if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
1637 result, &entities, &error))
1639 DEBUG ("%s. Aborting", error->message);
1640 g_error_free (error);
1644 view = GTK_TREE_VIEW (ctx->window->treeview_who);
1645 model = gtk_tree_view_get_model (view);
1646 selection = gtk_tree_view_get_selection (view);
1647 store = GTK_LIST_STORE (model);
1649 /* Block signals to stop the logs being retrieved prematurely */
1650 g_signal_handlers_block_by_func (selection,
1651 log_window_who_changed_cb, ctx->window);
1653 for (l = entities; l; l = l->next)
1655 TplEntity *entity = TPL_ENTITY (l->data);
1656 TplEntityType type = tpl_entity_get_entity_type (entity);
1657 gboolean room = type == TPL_ENTITY_ROOM;
1659 gtk_list_store_append (store, &iter);
1660 gtk_list_store_set (store, &iter,
1661 COL_WHO_TYPE, COL_TYPE_NORMAL,
1662 COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
1663 : EMPATHY_IMAGE_AVATAR_DEFAULT,
1664 COL_WHO_NAME, tpl_entity_get_alias (entity),
1665 COL_WHO_ACCOUNT, ctx->account,
1666 COL_WHO_TARGET, entity,
1669 if (ctx->window->selected_account != NULL &&
1670 !tp_strdiff (tp_proxy_get_object_path (ctx->account),
1671 tp_proxy_get_object_path (ctx->window->selected_account)))
1672 select_account = TRUE;
1674 g_list_free_full (entities, g_object_unref);
1676 if (gtk_tree_model_get_iter_first (model, &iter))
1680 gtk_tree_model_get (model, &iter,
1681 COL_WHO_TYPE, &type,
1684 if (type != COL_TYPE_ANY)
1686 gtk_list_store_prepend (store, &iter);
1687 gtk_list_store_set (store, &iter,
1688 COL_WHO_TYPE, COL_TYPE_SEPARATOR,
1689 COL_WHO_NAME, "separator",
1692 gtk_list_store_prepend (store, &iter);
1693 gtk_list_store_set (store, &iter,
1694 COL_WHO_TYPE, COL_TYPE_ANY,
1695 COL_WHO_NAME, _("Anyone"),
1700 /* Unblock signals */
1701 g_signal_handlers_unblock_by_func (selection,
1702 log_window_who_changed_cb,
1705 /* We display the selected account if we populate the model with chats from
1708 log_window_chats_set_selected (ctx->window);
1711 _tpl_action_chain_continue (log_window->chain);
1716 get_entities_for_account (TplActionChain *chain, gpointer user_data)
1718 Ctx *ctx = user_data;
1720 tpl_log_manager_get_entities_async (ctx->window->log_manager, ctx->account,
1721 log_manager_got_entities_cb, ctx);
1725 select_first_entity (TplActionChain *chain, gpointer user_data)
1728 GtkTreeModel *model;
1729 GtkTreeSelection *selection;
1732 view = GTK_TREE_VIEW (log_window->treeview_who);
1733 model = gtk_tree_view_get_model (view);
1734 selection = gtk_tree_view_get_selection (view);
1736 if (gtk_tree_model_get_iter_first (model, &iter))
1737 gtk_tree_selection_select_iter (selection, &iter);
1739 _tpl_action_chain_continue (log_window->chain);
1743 log_window_who_populate (EmpathyLogWindow *window)
1745 EmpathyAccountChooser *account_chooser;
1747 gboolean all_accounts;
1749 GtkTreeModel *model;
1750 GtkTreeSelection *selection;
1751 GtkListStore *store;
1754 if (window->hits != NULL)
1756 populate_entities_from_search_hits ();
1760 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
1761 account = empathy_account_chooser_dup_account (account_chooser);
1762 all_accounts = empathy_account_chooser_has_all_selected (account_chooser);
1764 view = GTK_TREE_VIEW (window->treeview_who);
1765 model = gtk_tree_view_get_model (view);
1766 selection = gtk_tree_view_get_selection (view);
1767 store = GTK_LIST_STORE (model);
1769 /* Block signals to stop the logs being retrieved prematurely */
1770 g_signal_handlers_block_by_func (selection,
1771 log_window_who_changed_cb,
1774 gtk_list_store_clear (store);
1776 /* Unblock signals */
1777 g_signal_handlers_unblock_by_func (selection,
1778 log_window_who_changed_cb,
1781 _tpl_action_chain_clear (window->chain);
1784 if (!all_accounts && account == NULL)
1788 else if (!all_accounts)
1790 ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
1791 _tpl_action_chain_append (window->chain, get_entities_for_account, ctx);
1795 TpAccountManager *manager;
1796 GList *accounts, *l;
1798 manager = empathy_account_chooser_get_account_manager (account_chooser);
1799 accounts = tp_account_manager_get_valid_accounts (manager);
1801 for (l = accounts; l != NULL; l = l->next)
1805 ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
1806 _tpl_action_chain_append (window->chain,
1807 get_entities_for_account, ctx);
1810 g_list_free (accounts);
1812 _tpl_action_chain_append (window->chain, select_first_entity, NULL);
1813 _tpl_action_chain_start (window->chain);
1817 sort_by_name (GtkTreeModel *model,
1822 gchar *name1, *name2;
1826 gtk_tree_model_get (model, a,
1827 COL_WHO_TYPE, &type1,
1828 COL_WHO_NAME, &name1,
1831 gtk_tree_model_get (model, b,
1832 COL_WHO_TYPE, &type2,
1833 COL_WHO_NAME, &name2,
1836 if (type1 == COL_TYPE_ANY)
1838 else if (type2 == COL_TYPE_ANY)
1840 else if (type1 == COL_TYPE_SEPARATOR)
1842 else if (type2 == COL_TYPE_SEPARATOR)
1845 ret = g_strcmp0 (name1, name2);
1854 who_row_is_separator (GtkTreeModel *model,
1860 gtk_tree_model_get (model, iter,
1861 COL_WHO_TYPE, &type,
1864 return (type == COL_TYPE_SEPARATOR);
1868 log_window_events_setup (EmpathyLogWindow *window)
1871 GtkTreeModel *model;
1872 GtkTreeSelection *selection;
1873 GtkTreeSortable *sortable;
1874 GtkTreeViewColumn *column;
1875 GtkTreeStore *store;
1876 GtkCellRenderer *cell;
1878 view = GTK_TREE_VIEW (window->treeview_events);
1879 selection = gtk_tree_view_get_selection (view);
1882 window->store_events = store = gtk_tree_store_new (COL_EVENTS_COUNT,
1883 G_TYPE_INT, /* type */
1884 G_TYPE_INT64, /* timestamp */
1885 G_TYPE_STRING, /* stringified date */
1886 G_TYPE_STRING, /* icon */
1887 G_TYPE_STRING, /* name */
1888 TP_TYPE_ACCOUNT, /* account */
1889 TPL_TYPE_ENTITY, /* target */
1890 TPL_TYPE_EVENT); /* event */
1892 model = GTK_TREE_MODEL (store);
1893 sortable = GTK_TREE_SORTABLE (store);
1895 gtk_tree_view_set_model (view, model);
1898 column = gtk_tree_view_column_new ();
1900 cell = gtk_cell_renderer_pixbuf_new ();
1901 gtk_tree_view_column_pack_start (column, cell, FALSE);
1902 gtk_tree_view_column_add_attribute (column, cell,
1903 "icon-name", COL_EVENTS_ICON);
1905 cell = gtk_cell_renderer_text_new ();
1906 gtk_tree_view_column_pack_start (column, cell, TRUE);
1907 gtk_tree_view_column_add_attribute (column, cell,
1908 "markup", COL_EVENTS_TEXT);
1910 cell = gtk_cell_renderer_text_new ();
1911 g_object_set (cell, "xalign", 1.0, NULL);
1912 gtk_tree_view_column_pack_end (column, cell, FALSE);
1913 gtk_tree_view_column_add_attribute (column, cell,
1914 "text", COL_EVENTS_PRETTY_DATE);
1916 gtk_tree_view_append_column (view, column);
1918 /* set up treeview properties */
1919 gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
1920 gtk_tree_view_set_headers_visible (view, FALSE);
1922 gtk_tree_sortable_set_sort_column_id (sortable,
1924 GTK_SORT_ASCENDING);
1926 gtk_tree_view_set_enable_search (view, FALSE);
1928 g_object_unref (store);
1932 log_window_who_setup (EmpathyLogWindow *window)
1935 GtkTreeModel *model;
1936 GtkTreeSelection *selection;
1937 GtkTreeSortable *sortable;
1938 GtkTreeViewColumn *column;
1939 GtkListStore *store;
1940 GtkCellRenderer *cell;
1942 view = GTK_TREE_VIEW (window->treeview_who);
1943 selection = gtk_tree_view_get_selection (view);
1946 store = gtk_list_store_new (COL_WHO_COUNT,
1947 G_TYPE_INT, /* type */
1948 G_TYPE_STRING, /* icon */
1949 G_TYPE_STRING, /* name */
1950 TP_TYPE_ACCOUNT, /* account */
1951 TPL_TYPE_ENTITY); /* target */
1953 model = GTK_TREE_MODEL (store);
1954 sortable = GTK_TREE_SORTABLE (store);
1956 gtk_tree_view_set_model (view, model);
1959 column = gtk_tree_view_column_new ();
1960 gtk_tree_view_column_set_title (column, _("Who"));
1962 cell = gtk_cell_renderer_pixbuf_new ();
1963 gtk_tree_view_column_pack_start (column, cell, FALSE);
1964 gtk_tree_view_column_add_attribute (column, cell,
1968 cell = gtk_cell_renderer_text_new ();
1969 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1970 gtk_tree_view_column_pack_start (column, cell, TRUE);
1971 gtk_tree_view_column_add_attribute (column, cell,
1975 gtk_tree_view_append_column (view, column);
1977 /* set up treeview properties */
1978 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1979 gtk_tree_view_set_row_separator_func (view, who_row_is_separator,
1982 gtk_tree_sortable_set_sort_column_id (sortable,
1984 GTK_SORT_ASCENDING);
1985 gtk_tree_sortable_set_sort_func (sortable,
1986 COL_WHO_NAME, sort_by_name,
1989 gtk_tree_view_set_search_column (view, COL_WHO_NAME);
1991 /* set up signals */
1992 g_signal_connect (selection, "changed",
1993 G_CALLBACK (log_window_who_changed_cb), window);
1995 g_object_unref (store);
1999 log_window_chats_accounts_changed_cb (GtkWidget *combobox,
2000 EmpathyLogWindow *window)
2002 /* Clear all current messages shown in the textview */
2003 gtk_tree_store_clear (window->store_events);
2005 log_window_who_populate (window);
2009 log_window_chats_set_selected (EmpathyLogWindow *window)
2012 GtkTreeModel *model;
2013 GtkTreeSelection *selection;
2018 view = GTK_TREE_VIEW (window->treeview_who);
2019 model = gtk_tree_view_get_model (view);
2020 selection = gtk_tree_view_get_selection (view);
2022 for (next = gtk_tree_model_get_iter_first (model, &iter);
2024 next = gtk_tree_model_iter_next (model, &iter))
2026 TpAccount *this_account;
2027 TplEntity *this_target;
2028 const gchar *this_chat_id;
2029 gboolean this_is_chatroom;
2032 gtk_tree_model_get (model, &iter,
2033 COL_WHO_TYPE, &this_type,
2034 COL_WHO_ACCOUNT, &this_account,
2035 COL_WHO_TARGET, &this_target,
2038 if (this_type != COL_TYPE_NORMAL)
2041 this_chat_id = tpl_entity_get_identifier (this_target);
2042 this_is_chatroom = tpl_entity_get_entity_type (this_target)
2045 if (this_account == window->selected_account &&
2046 !tp_strdiff (this_chat_id, window->selected_chat_id) &&
2047 this_is_chatroom == window->selected_is_chatroom)
2049 gtk_tree_selection_select_iter (selection, &iter);
2050 path = gtk_tree_model_get_path (model, &iter);
2051 gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
2052 gtk_tree_path_free (path);
2053 g_object_unref (this_account);
2054 g_object_unref (this_target);
2058 g_object_unref (this_account);
2059 g_object_unref (this_target);
2062 tp_clear_object (&window->selected_account);
2063 tp_clear_pointer (&window->selected_chat_id, g_free);
2067 sort_by_date (GtkTreeModel *model,
2072 GDate *date1, *date2;
2074 gtk_tree_model_get (model, a,
2075 COL_WHEN_DATE, &date1,
2078 gtk_tree_model_get (model, b,
2079 COL_WHEN_DATE, &date2,
2082 return g_date_compare (date1, date2);
2086 when_row_is_separator (GtkTreeModel *model,
2093 gtk_tree_model_get (model, iter,
2094 COL_WHEN_TEXT, &when,
2097 ret = g_str_equal (when, "separator");
2103 log_window_when_changed_cb (GtkTreeSelection *selection,
2104 EmpathyLogWindow *window)
2107 GtkTreeModel *model;
2110 DEBUG ("log_window_when_changed_cb");
2112 view = gtk_tree_selection_get_tree_view (selection);
2113 model = gtk_tree_view_get_model (view);
2115 /* If 'Anytime' is selected, everything else should be deselected */
2116 if (gtk_tree_model_get_iter_first (model, &iter))
2118 if (gtk_tree_selection_iter_is_selected (selection, &iter))
2120 g_signal_handlers_block_by_func (selection,
2121 log_window_when_changed_cb,
2124 gtk_tree_selection_unselect_all (selection);
2125 gtk_tree_selection_select_iter (selection, &iter);
2127 g_signal_handlers_unblock_by_func (selection,
2128 log_window_when_changed_cb,
2133 log_window_chats_get_messages (window, FALSE);
2137 log_window_when_setup (EmpathyLogWindow *window)
2140 GtkTreeModel *model;
2141 GtkTreeSelection *selection;
2142 GtkTreeSortable *sortable;
2143 GtkTreeViewColumn *column;
2144 GtkListStore *store;
2145 GtkCellRenderer *cell;
2147 view = GTK_TREE_VIEW (window->treeview_when);
2148 selection = gtk_tree_view_get_selection (view);
2151 store = gtk_list_store_new (COL_WHEN_COUNT,
2152 G_TYPE_DATE, /* date */
2153 G_TYPE_STRING, /* stringified date */
2154 G_TYPE_STRING); /* icon */
2156 model = GTK_TREE_MODEL (store);
2157 sortable = GTK_TREE_SORTABLE (store);
2159 gtk_tree_view_set_model (view, model);
2162 column = gtk_tree_view_column_new ();
2163 gtk_tree_view_column_set_title (column, _("When"));
2165 cell = gtk_cell_renderer_pixbuf_new ();
2166 gtk_tree_view_column_pack_start (column, cell, FALSE);
2167 gtk_tree_view_column_add_attribute (column, cell,
2168 "icon-name", COL_WHEN_ICON);
2170 cell = gtk_cell_renderer_text_new ();
2171 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2172 gtk_tree_view_column_pack_start (column, cell, TRUE);
2173 gtk_tree_view_column_add_attribute (column, cell,
2177 gtk_tree_view_append_column (view, column);
2179 /* set up treeview properties */
2180 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2181 gtk_tree_view_set_row_separator_func (view, when_row_is_separator,
2183 gtk_tree_sortable_set_sort_column_id (sortable,
2185 GTK_SORT_DESCENDING);
2186 gtk_tree_sortable_set_sort_func (sortable,
2187 COL_WHEN_DATE, sort_by_date,
2190 gtk_tree_view_set_search_column (view, COL_WHEN_TEXT);
2192 /* set up signals */
2193 g_signal_connect (selection, "changed",
2194 G_CALLBACK (log_window_when_changed_cb),
2197 g_object_unref (store);
2201 what_row_is_separator (GtkTreeModel *model,
2207 gtk_tree_model_get (model, iter,
2208 COL_WHAT_TYPE, &type,
2211 return (type == WHAT_TYPE_SEPARATOR);
2215 log_window_what_changed_cb (GtkTreeSelection *selection,
2216 EmpathyLogWindow *window)
2219 GtkTreeModel *model;
2222 DEBUG ("log_window_what_changed_cb");
2224 view = gtk_tree_selection_get_tree_view (selection);
2225 model = gtk_tree_view_get_model (view);
2227 /* If 'Anything' is selected, everything else should be deselected */
2228 if (gtk_tree_model_get_iter_first (model, &iter))
2230 if (gtk_tree_selection_iter_is_selected (selection, &iter))
2232 g_signal_handlers_block_by_func (selection,
2233 log_window_what_changed_cb,
2236 gtk_tree_selection_unselect_all (selection);
2237 gtk_tree_selection_select_iter (selection, &iter);
2239 g_signal_handlers_unblock_by_func (selection,
2240 log_window_what_changed_cb,
2245 /* The dates need to be updated if we're not searching */
2246 log_window_chats_get_messages (window, window->hits == NULL);
2250 log_window_what_collapse_row_cb (GtkTreeView *tree_view,
2255 /* Reject collapsing */
2262 EventSubtype subtype;
2268 log_window_what_setup (EmpathyLogWindow *window)
2271 GtkTreeModel *model;
2272 GtkTreeSelection *selection;
2273 GtkTreeViewColumn *column;
2275 GtkTreeStore *store;
2276 GtkCellRenderer *cell;
2278 struct event events [] = {
2279 { TPL_EVENT_MASK_ANY, 0, NULL, _("Anything") },
2280 { WHAT_TYPE_SEPARATOR, 0, NULL, "separator" },
2281 { TPL_EVENT_MASK_TEXT, 0, "stock_text_justify", _("Text chats") },
2282 #ifdef HAVE_CALL_LOGS
2283 { TPL_EVENT_MASK_CALL, EVENT_CALL_ALL, EMPATHY_IMAGE_CALL, _("Calls") },
2286 #ifdef HAVE_CALL_LOGS
2287 struct event call_events [] = {
2288 { TPL_EVENT_MASK_CALL, EVENT_CALL_INCOMING, EMPATHY_IMAGE_CALL_INCOMING, _("Incoming calls") },
2289 { TPL_EVENT_MASK_CALL, EVENT_CALL_OUTGOING, EMPATHY_IMAGE_CALL_OUTGOING, _("Outgoing calls") },
2290 { TPL_EVENT_MASK_CALL, EVENT_CALL_MISSED, EMPATHY_IMAGE_CALL_MISSED, _("Missed calls") }
2295 view = GTK_TREE_VIEW (window->treeview_what);
2296 selection = gtk_tree_view_get_selection (view);
2299 store = gtk_tree_store_new (COL_WHAT_COUNT,
2300 G_TYPE_INT, /* history type */
2301 G_TYPE_INT, /* history subtype */
2302 G_TYPE_STRING, /* stringified history type */
2303 G_TYPE_STRING); /* icon */
2305 model = GTK_TREE_MODEL (store);
2307 gtk_tree_view_set_model (view, model);
2310 column = gtk_tree_view_column_new ();
2311 gtk_tree_view_column_set_title (column, _("What"));
2313 cell = gtk_cell_renderer_pixbuf_new ();
2314 gtk_tree_view_column_pack_start (column, cell, FALSE);
2315 gtk_tree_view_column_add_attribute (column, cell,
2316 "icon-name", COL_WHAT_ICON);
2318 cell = gtk_cell_renderer_text_new ();
2319 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2320 gtk_tree_view_column_pack_start (column, cell, TRUE);
2321 gtk_tree_view_column_add_attribute (column, cell,
2322 "text", COL_WHAT_TEXT);
2324 gtk_tree_view_append_column (view, column);
2325 gtk_tree_view_set_search_column (view, COL_WHAT_TEXT);
2327 /* set up treeview properties */
2328 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2329 gtk_tree_view_set_show_expanders (view, FALSE);
2330 gtk_tree_view_set_level_indentation (view, 12);
2331 gtk_tree_view_expand_all (view);
2332 gtk_tree_view_set_row_separator_func (view, what_row_is_separator,
2336 for (i = 0; i < G_N_ELEMENTS (events); i++)
2338 gtk_tree_store_append (store, &iter, NULL);
2339 gtk_tree_store_set (store, &iter,
2340 COL_WHAT_TYPE, events[i].type,
2341 COL_WHAT_SUBTYPE, events[i].subtype,
2342 COL_WHAT_TEXT, events[i].text,
2343 COL_WHAT_ICON, events[i].icon,
2347 #ifdef HAVE_CALL_LOGS
2348 gtk_tree_model_iter_nth_child (model, &parent, NULL, 3);
2349 for (i = 0; i < G_N_ELEMENTS (call_events); i++)
2351 gtk_tree_store_append (store, &iter, &parent);
2352 gtk_tree_store_set (store, &iter,
2353 COL_WHAT_TYPE, call_events[i].type,
2354 COL_WHAT_SUBTYPE, call_events[i].subtype,
2355 COL_WHAT_TEXT, call_events[i].text,
2356 COL_WHAT_ICON, call_events[i].icon,
2361 gtk_tree_view_expand_all (view);
2363 /* select 'Anything' */
2364 if (gtk_tree_model_get_iter_first (model, &iter))
2365 gtk_tree_selection_select_iter (selection, &iter);
2367 /* set up signals */
2368 g_signal_connect (view, "test-collapse-row",
2369 G_CALLBACK (log_window_what_collapse_row_cb),
2371 g_signal_connect (selection, "changed",
2372 G_CALLBACK (log_window_what_changed_cb),
2375 g_object_unref (store);
2379 start_spinner (void)
2381 gtk_spinner_start (GTK_SPINNER (log_window->spinner));
2382 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2387 show_spinner (gpointer data)
2391 if (log_window == NULL)
2394 g_object_get (log_window->spinner, "active", &active, NULL);
2397 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2404 show_events (TplActionChain *chain,
2407 gtk_spinner_stop (GTK_SPINNER (log_window->spinner));
2408 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2411 _tpl_action_chain_continue (chain);
2415 log_window_got_messages_for_date_cb (GObject *manager,
2416 GAsyncResult *result,
2419 Ctx *ctx = user_data;
2421 GtkTreeModel *model;
2425 GError *error = NULL;
2428 if (log_window == NULL)
2434 if (log_window->count != ctx->count)
2437 if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (manager),
2438 result, &events, &error))
2440 DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting",
2442 g_error_free (error);
2446 for (l = events; l; l = l->next)
2448 TplEvent *event = l->data;
2449 gboolean append = TRUE;
2451 #ifdef HAVE_CALL_LOGS
2452 if (TPL_IS_CALL_EVENT (l->data)
2453 && ctx->event_mask & TPL_EVENT_MASK_CALL
2454 && ctx->event_mask != TPL_EVENT_MASK_ANY)
2456 TplCallEvent *call = l->data;
2460 if (ctx->subtype & EVENT_CALL_ALL)
2466 TplCallEndReason reason = tpl_call_event_get_end_reason (call);
2467 TplEntity *sender = tpl_event_get_sender (event);
2468 TplEntity *receiver = tpl_event_get_receiver (event);
2470 if (reason == TPL_CALL_END_REASON_NO_ANSWER)
2472 if (ctx->subtype & EVENT_CALL_MISSED)
2475 else if (ctx->subtype & EVENT_CALL_OUTGOING
2476 && tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
2480 else if (ctx->subtype & EVENT_CALL_INCOMING
2481 && tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
2491 EmpathyMessage *msg = empathy_message_from_tpl_log_event (event);
2492 log_window_append_message (event, msg);
2493 tp_clear_object (&msg);
2496 g_object_unref (event);
2498 g_list_free (events);
2500 view = GTK_TREE_VIEW (log_window->treeview_events);
2501 model = gtk_tree_view_get_model (view);
2502 n = gtk_tree_model_iter_n_children (model, NULL) - 1;
2504 if (n >= 0 && gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
2508 path = gtk_tree_model_get_path (model, &iter);
2509 gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0, 0);
2510 gtk_tree_path_free (path);
2516 _tpl_action_chain_continue (log_window->chain);
2520 get_events_for_date (TplActionChain *chain, gpointer user_data)
2522 Ctx *ctx = user_data;
2524 tpl_log_manager_get_events_for_date_async (ctx->window->log_manager,
2525 ctx->account, ctx->entity, ctx->event_mask,
2527 log_window_got_messages_for_date_cb,
2532 log_window_get_messages_for_dates (EmpathyLogWindow *window,
2535 GList *accounts, *targets, *acc, *targ, *l;
2536 TplEventTypeMask event_mask;
2537 EventSubtype subtype;
2538 GDate *date, *anytime, *separator;
2540 if (!log_window_get_selected (window,
2541 &accounts, &targets, NULL, &event_mask, &subtype))
2544 anytime = g_date_new_dmy (2, 1, -1);
2545 separator = g_date_new_dmy (1, 1, -1);
2547 _tpl_action_chain_clear (window->chain);
2550 for (acc = accounts, targ = targets;
2551 acc != NULL && targ != NULL;
2552 acc = acc->next, targ = targ->next)
2554 TpAccount *account = acc->data;
2555 TplEntity *target = targ->data;
2557 for (l = dates; l != NULL; l = l->next)
2562 if (g_date_compare (date, anytime) != 0)
2566 ctx = ctx_new (window, account, target, date, event_mask, subtype,
2568 _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
2572 GtkTreeView *view = GTK_TREE_VIEW (window->treeview_when);
2573 GtkTreeModel *model = gtk_tree_view_get_model (view);
2578 for (next = gtk_tree_model_get_iter_first (model, &iter);
2580 next = gtk_tree_model_iter_next (model, &iter))
2584 gtk_tree_model_get (model, &iter,
2588 if (g_date_compare (d, anytime) != 0 &&
2589 g_date_compare (d, separator) != 0)
2591 ctx = ctx_new (window, account, target, d,
2592 event_mask, subtype, window->count);
2593 _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
2601 g_timeout_add (1000, show_spinner, NULL);
2602 _tpl_action_chain_append (window->chain, show_events, NULL);
2603 _tpl_action_chain_start (window->chain);
2605 g_list_free_full (accounts, g_object_unref);
2606 g_list_free_full (targets, g_object_unref);
2607 g_date_free (separator);
2608 g_date_free (anytime);
2612 log_manager_got_dates_cb (GObject *manager,
2613 GAsyncResult *result,
2616 Ctx *ctx = user_data;
2618 GtkTreeModel *model;
2619 GtkListStore *store;
2623 GError *error = NULL;
2625 if (log_window == NULL)
2628 if (log_window->count != ctx->count)
2631 if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager),
2632 result, &dates, &error))
2634 DEBUG ("Unable to retrieve messages' dates: %s. Aborting",
2639 view = GTK_TREE_VIEW (log_window->treeview_when);
2640 model = gtk_tree_view_get_model (view);
2641 store = GTK_LIST_STORE (model);
2643 for (l = dates; l != NULL; l = l->next)
2645 GDate *date = l->data;
2647 /* Add the date if it's not already there */
2648 has_element = FALSE;
2649 gtk_tree_model_foreach (model, model_has_date, date);
2652 gchar *text = format_date_for_display (date);
2654 gtk_list_store_append (store, &iter);
2655 gtk_list_store_set (store, &iter,
2656 COL_WHEN_DATE, date,
2657 COL_WHEN_TEXT, text,
2658 COL_WHEN_ICON, CALENDAR_ICON,
2665 if (gtk_tree_model_get_iter_first (model, &iter))
2667 gchar *separator = NULL;
2669 if (gtk_tree_model_iter_next (model, &iter))
2671 gtk_tree_model_get (model, &iter,
2672 COL_WHEN_TEXT, &separator,
2676 if (g_strcmp0 (separator, "separator") != 0)
2678 gtk_list_store_prepend (store, &iter);
2679 gtk_list_store_set (store, &iter,
2680 COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
2681 COL_WHEN_TEXT, "separator",
2684 gtk_list_store_prepend (store, &iter);
2685 gtk_list_store_set (store, &iter,
2686 COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
2687 COL_WHEN_TEXT, _("Anytime"),
2692 g_list_free_full (dates, g_free);
2695 _tpl_action_chain_continue (log_window->chain);
2699 select_first_date (TplActionChain *chain, gpointer user_data)
2702 GtkTreeModel *model;
2703 GtkTreeSelection *selection;
2706 view = GTK_TREE_VIEW (log_window->treeview_when);
2707 model = gtk_tree_view_get_model (view);
2708 selection = gtk_tree_view_get_selection (view);
2710 /* Show messages of the most recent date */
2711 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 2))
2712 gtk_tree_selection_select_iter (selection, &iter);
2714 _tpl_action_chain_continue (log_window->chain);
2718 get_dates_for_entity (TplActionChain *chain, gpointer user_data)
2720 Ctx *ctx = user_data;
2722 tpl_log_manager_get_dates_async (ctx->window->log_manager,
2723 ctx->account, ctx->entity, ctx->event_mask,
2724 log_manager_got_dates_cb, ctx);
2728 log_window_chats_get_messages (EmpathyLogWindow *window,
2729 gboolean force_get_dates)
2731 GList *accounts, *targets, *dates;
2732 TplEventTypeMask event_mask;
2734 GtkTreeModel *model;
2735 GtkListStore *store;
2736 GtkTreeSelection *selection;
2738 if (!log_window_get_selected (window, &accounts, &targets,
2739 &dates, &event_mask, NULL))
2742 view = GTK_TREE_VIEW (window->treeview_when);
2743 selection = gtk_tree_view_get_selection (view);
2744 model = gtk_tree_view_get_model (view);
2745 store = GTK_LIST_STORE (model);
2747 /* Clear all current messages shown in the textview */
2748 gtk_tree_store_clear (window->store_events);
2750 _tpl_action_chain_clear (window->chain);
2753 /* If there's a search use the returned hits */
2754 if (window->hits != NULL)
2756 if (force_get_dates)
2758 g_signal_handlers_block_by_func (selection,
2759 log_window_when_changed_cb,
2762 gtk_list_store_clear (store);
2764 g_signal_handlers_unblock_by_func (selection,
2765 log_window_when_changed_cb,
2768 populate_dates_from_search_hits (accounts, targets);
2772 populate_events_from_search_hits (accounts, targets, dates);
2775 /* Either use the supplied date or get the last */
2776 else if (force_get_dates || dates == NULL)
2780 g_signal_handlers_block_by_func (selection,
2781 log_window_when_changed_cb,
2784 gtk_list_store_clear (store);
2786 g_signal_handlers_unblock_by_func (selection,
2787 log_window_when_changed_cb,
2790 /* Get a list of dates and show them on the treeview */
2791 for (targ = targets, acc = accounts;
2792 targ != NULL && acc != NULL;
2793 targ = targ->next, acc = acc->next)
2795 TpAccount *account = acc->data;
2796 TplEntity *target = targ->data;
2797 Ctx *ctx = ctx_new (window, account, target, NULL, event_mask, 0,
2800 _tpl_action_chain_append (window->chain, get_dates_for_entity, ctx);
2802 _tpl_action_chain_append (window->chain, select_first_date, NULL);
2803 _tpl_action_chain_start (window->chain);
2807 /* Show messages of the selected date */
2808 log_window_get_messages_for_dates (window, dates);
2811 g_list_free_full (accounts, g_object_unref);
2812 g_list_free_full (targets, g_object_unref);
2813 g_list_free_full (dates, (GFreeFunc) g_date_free);
2817 EmpathyAccountChooserFilterResultCallback callback;
2819 } FilterCallbackData;
2822 got_entities (GObject *manager,
2823 GAsyncResult *result,
2826 FilterCallbackData *data = user_data;
2828 GError *error = NULL;
2830 if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
2831 result, &entities, &error))
2833 DEBUG ("Could not get entities: %s", error->message);
2834 g_error_free (error);
2835 data->callback (FALSE, data->user_data);
2839 data->callback (entities != NULL, data->user_data);
2841 g_list_free_full (entities, g_object_unref);
2844 g_slice_free (FilterCallbackData, data);
2848 empathy_account_chooser_filter_has_logs (TpAccount *account,
2849 EmpathyAccountChooserFilterResultCallback callback,
2850 gpointer callback_data,
2853 TplLogManager *manager = tpl_log_manager_dup_singleton ();
2854 FilterCallbackData *cb_data = g_slice_new0 (FilterCallbackData);
2856 cb_data->callback = callback;
2857 cb_data->user_data = callback_data;
2859 tpl_log_manager_get_entities_async (manager, account, got_entities, cb_data);
2861 g_object_unref (manager);
2865 log_window_logger_clear_account_cb (TpProxy *proxy,
2866 const GError *error,
2868 GObject *weak_object)
2870 EmpathyLogWindow *window = user_data;
2873 g_warning ("Error when clearing logs: %s", error->message);
2875 /* Refresh the log viewer so the logs are cleared if the account
2876 * has been deleted */
2877 gtk_tree_store_clear (window->store_events);
2878 log_window_who_populate (window);
2880 /* Re-filter the account chooser so the accounts without logs get greyed out */
2881 empathy_account_chooser_set_filter (
2882 EMPATHY_ACCOUNT_CHOOSER (window->account_chooser),
2883 empathy_account_chooser_filter_has_logs, NULL);
2887 log_window_clear_logs_chooser_select_account (EmpathyAccountChooser *chooser,
2888 EmpathyLogWindow *window)
2890 EmpathyAccountChooser *account_chooser;
2892 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
2894 empathy_account_chooser_set_account (chooser,
2895 empathy_account_chooser_get_account (account_chooser));
2899 log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
2900 EmpathyLogWindow *window)
2902 GtkWidget *dialog, *content_area, *hbox, *label;
2903 EmpathyAccountChooser *account_chooser;
2907 GError *error = NULL;
2909 account_chooser = (EmpathyAccountChooser *) empathy_account_chooser_new ();
2910 empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
2911 empathy_account_chooser_set_filter (account_chooser,
2912 empathy_account_chooser_filter_has_logs, NULL);
2914 /* Select the same account as in the history window */
2915 if (empathy_account_chooser_is_ready (account_chooser))
2916 log_window_clear_logs_chooser_select_account (account_chooser, window);
2918 g_signal_connect (account_chooser, "ready",
2919 G_CALLBACK (log_window_clear_logs_chooser_select_account), window);
2921 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window->window),
2922 GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
2924 _("Are you sure you want to delete all logs of previous conversations?"));
2926 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2927 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2928 _("Clear All"), GTK_RESPONSE_APPLY,
2931 content_area = gtk_message_dialog_get_message_area (
2932 GTK_MESSAGE_DIALOG (dialog));
2934 hbox = gtk_hbox_new (FALSE, 6);
2935 label = gtk_label_new (_("Delete from:"));
2936 gtk_box_pack_start (GTK_BOX (hbox), label,
2938 gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (account_chooser),
2940 gtk_box_pack_start (GTK_BOX (content_area), hbox,
2943 gtk_widget_show_all (hbox);
2945 response_id = gtk_dialog_run (GTK_DIALOG (dialog));
2947 if (response_id != GTK_RESPONSE_APPLY)
2950 bus = tp_dbus_daemon_dup (&error);
2953 g_warning ("Could not delete logs: %s", error->message);
2954 g_error_free (error);
2958 logger = g_object_new (TP_TYPE_PROXY,
2959 "bus-name", "org.freedesktop.Telepathy.Logger",
2960 "object-path", "/org/freedesktop/Telepathy/Logger",
2963 g_object_unref (bus);
2965 tp_proxy_add_interface_by_id (logger, EMP_IFACE_QUARK_LOGGER);
2967 if (empathy_account_chooser_has_all_selected (account_chooser))
2969 DEBUG ("Deleting logs for all the accounts");
2971 emp_cli_logger_call_clear (logger, -1,
2972 log_window_logger_clear_account_cb,
2973 window, NULL, G_OBJECT (window->window));
2979 account = empathy_account_chooser_get_account (account_chooser);
2981 DEBUG ("Deleting logs for %s", tp_proxy_get_object_path (account));
2983 emp_cli_logger_call_clear_account (logger, -1,
2984 tp_proxy_get_object_path (account),
2985 log_window_logger_clear_account_cb,
2986 window, NULL, G_OBJECT (window->window));
2989 g_object_unref (logger);
2991 gtk_widget_destroy (dialog);