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>
37 #include <telepathy-logger/call-event.h>
39 #include <extensions/extensions.h>
41 #include <libempathy/action-chain-internal.h>
42 #include <libempathy/empathy-chatroom-manager.h>
43 #include <libempathy/empathy-chatroom.h>
44 #include <libempathy/empathy-message.h>
45 #include <libempathy/empathy-request-util.h>
46 #include <libempathy/empathy-utils.h>
47 #include <libempathy/empathy-time.h>
49 #include "empathy-log-window.h"
50 #include "empathy-account-chooser.h"
51 #include "empathy-call-utils.h"
52 #include "empathy-chat-view.h"
53 #include "empathy-contact-dialogs.h"
54 #include "empathy-images.h"
55 #include "empathy-theme-manager.h"
56 #include "empathy-ui-utils.h"
58 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
59 #include <libempathy/empathy-debug.h>
65 GtkWidget *button_profile;
66 GtkWidget *button_chat;
67 GtkWidget *button_call;
68 GtkWidget *button_video;
70 GtkWidget *search_entry;
75 GtkWidget *treeview_who;
76 GtkWidget *treeview_what;
77 GtkWidget *treeview_when;
78 GtkWidget *treeview_events;
80 GtkTreeStore *store_events;
82 GtkWidget *account_chooser;
86 TplActionChain *chain;
87 TplLogManager *log_manager;
89 /* Used to cancel logger calls when no longer needed */
92 /* List of owned TplLogSearchHits, free with tpl_log_search_hit_free */
96 /* Only used while waiting for the account chooser to be ready */
97 TpAccount *selected_account;
98 gchar *selected_chat_id;
99 gboolean selected_is_chatroom;
102 static void log_window_destroy_cb (GtkWidget *widget,
103 EmpathyLogWindow *window);
104 static void log_window_search_entry_changed_cb (GtkWidget *entry,
105 EmpathyLogWindow *window);
106 static void log_window_search_entry_activate_cb (GtkWidget *widget,
107 EmpathyLogWindow *window);
108 static void log_window_search_entry_icon_pressed_cb (GtkEntry *entry,
109 GtkEntryIconPosition icon_pos,
112 static void log_window_who_populate (EmpathyLogWindow *window);
113 static void log_window_who_setup (EmpathyLogWindow *window);
114 static void log_window_when_setup (EmpathyLogWindow *window);
115 static void log_window_what_setup (EmpathyLogWindow *window);
116 static void log_window_events_setup (EmpathyLogWindow *window);
117 static void log_window_chats_accounts_changed_cb (GtkWidget *combobox,
118 EmpathyLogWindow *window);
119 static void log_window_chats_set_selected (EmpathyLogWindow *window);
120 static void log_window_chats_get_messages (EmpathyLogWindow *window,
121 gboolean force_get_dates);
122 static void log_window_when_changed_cb (GtkTreeSelection *selection,
123 EmpathyLogWindow *window);
124 static void log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
125 EmpathyLogWindow *window);
128 empathy_account_chooser_filter_has_logs (TpAccount *account,
129 EmpathyAccountChooserFilterResultCallback callback,
130 gpointer callback_data,
178 COL_EVENTS_PRETTY_DATE,
187 #define CALENDAR_ICON "stock_calendar"
189 /* Seconds between two messages to be considered one conversation */
190 #define MAX_GAP 30*60
192 #define WHAT_TYPE_SEPARATOR -1
196 EVENT_CALL_INCOMING = 1 << 0,
197 EVENT_CALL_OUTGOING = 1 << 1,
198 EVENT_CALL_MISSED = 1 << 2,
199 EVENT_CALL_ALL = 1 << 3,
202 static EmpathyLogWindow *log_window = NULL;
204 static gboolean has_element;
207 #define _date_copy(d) g_date_new_julian (g_date_get_julian (d))
212 EmpathyLogWindow *window;
216 TplEventTypeMask event_mask;
217 EventSubtype subtype;
222 ctx_new (EmpathyLogWindow *window,
226 TplEventTypeMask event_mask,
227 EventSubtype subtype,
230 Ctx *ctx = g_slice_new0 (Ctx);
232 ctx->window = window;
234 ctx->account = g_object_ref (account);
236 ctx->entity = g_object_ref (entity);
238 ctx->date = _date_copy (date);
239 ctx->event_mask = event_mask;
240 ctx->subtype = subtype;
249 tp_clear_object (&ctx->account);
250 tp_clear_object (&ctx->entity);
251 tp_clear_pointer (&ctx->date, g_date_free);
253 g_slice_free (Ctx, ctx);
257 account_chooser_ready_cb (EmpathyAccountChooser *chooser,
258 EmpathyLogWindow *window)
260 /* We'll display the account once the model has been populate with the chats
261 * of this account. */
262 empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (
263 window->account_chooser), window->selected_account);
267 select_account_once_ready (EmpathyLogWindow *self,
269 const gchar *chat_id,
270 gboolean is_chatroom)
272 EmpathyAccountChooser *account_chooser;
274 account_chooser = EMPATHY_ACCOUNT_CHOOSER (self->account_chooser);
276 tp_clear_object (&self->selected_account);
277 self->selected_account = g_object_ref (account);
279 g_free (self->selected_chat_id);
280 self->selected_chat_id = g_strdup (chat_id);
282 self->selected_is_chatroom = is_chatroom;
284 if (empathy_account_chooser_is_ready (account_chooser))
285 account_chooser_ready_cb (account_chooser, self);
287 /* Chat will be selected once the account chooser is ready */
288 g_signal_connect (account_chooser, "ready",
289 G_CALLBACK (account_chooser_ready_cb), self);
293 toolbutton_profile_clicked (GtkToolButton *toolbutton,
294 EmpathyLogWindow *window)
297 GtkTreeSelection *selection;
304 EmpathyContact *contact;
307 g_return_if_fail (window != NULL);
309 view = GTK_TREE_VIEW (log_window->treeview_who);
310 selection = gtk_tree_view_get_selection (view);
312 paths = gtk_tree_selection_get_selected_rows (selection, &model);
313 g_return_if_fail (paths != NULL);
316 gtk_tree_model_get_iter (model, &iter, path);
317 gtk_tree_model_get (model, &iter,
318 COL_WHO_ACCOUNT, &account,
319 COL_WHO_TARGET, &target,
323 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
325 g_return_if_fail (type == COL_TYPE_NORMAL);
327 contact = empathy_contact_from_tpl_contact (account, target);
328 empathy_contact_information_dialog_show (contact,
329 GTK_WINDOW (window->window));
330 g_object_unref (contact);
332 g_object_unref (account);
333 g_object_unref (target);
337 toolbutton_chat_clicked (GtkToolButton *toolbutton,
338 EmpathyLogWindow *window)
341 GtkTreeSelection *selection;
348 EmpathyContact *contact;
351 g_return_if_fail (window != NULL);
353 view = GTK_TREE_VIEW (log_window->treeview_who);
354 selection = gtk_tree_view_get_selection (view);
356 paths = gtk_tree_selection_get_selected_rows (selection, &model);
357 g_return_if_fail (paths != NULL);
360 gtk_tree_model_get_iter (model, &iter, path);
361 gtk_tree_model_get (model, &iter,
362 COL_WHO_ACCOUNT, &account,
363 COL_WHO_TARGET, &target,
367 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
369 g_return_if_fail (type == COL_TYPE_NORMAL);
371 contact = empathy_contact_from_tpl_contact (account, target);
372 empathy_chat_with_contact (contact,
373 gtk_get_current_event_time ());
375 g_object_unref (contact);
376 g_object_unref (account);
377 g_object_unref (target);
381 toolbutton_av_clicked (GtkToolButton *toolbutton,
382 EmpathyLogWindow *window)
385 GtkTreeSelection *selection;
395 g_return_if_fail (window != NULL);
397 view = GTK_TREE_VIEW (log_window->treeview_who);
398 selection = gtk_tree_view_get_selection (view);
400 paths = gtk_tree_selection_get_selected_rows (selection, &model);
401 g_return_if_fail (paths != NULL);
404 gtk_tree_model_get_iter (model, &iter, path);
405 gtk_tree_model_get (model, &iter,
406 COL_WHO_ACCOUNT, &account,
407 COL_WHO_NAME, &contact,
411 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
413 g_return_if_fail (type == COL_TYPE_NORMAL);
415 video = (GTK_WIDGET (toolbutton) == window->button_video);
417 empathy_call_new_with_streams (contact, account,
418 TRUE, video, gtk_get_current_event_time ());
421 g_object_unref (account);
425 empathy_log_window_show (TpAccount *account,
426 const gchar *chat_id,
427 gboolean is_chatroom,
430 EmpathyAccountChooser *account_chooser;
433 EmpathyLogWindow *window;
434 GtkWidget *vbox, *accounts, *search, *label, *quit;
436 if (log_window != NULL)
438 gtk_window_present (GTK_WINDOW (log_window->window));
440 if (account != NULL && chat_id != NULL)
441 select_account_once_ready (log_window, account, chat_id, is_chatroom);
443 return log_window->window;
446 log_window = g_new0 (EmpathyLogWindow, 1);
447 log_window->chain = _tpl_action_chain_new_async (NULL, NULL, NULL);
449 log_window->log_manager = tpl_log_manager_dup_singleton ();
453 filename = empathy_file_lookup ("empathy-log-window.ui", "libempathy-gtk");
454 gui = empathy_builder_get_file (filename,
455 "log_window", &window->window,
456 "toolbutton_profile", &window->button_profile,
457 "toolbutton_chat", &window->button_chat,
458 "toolbutton_call", &window->button_call,
459 "toolbutton_video", &window->button_video,
460 "toolbutton_accounts", &accounts,
461 "toolbutton_search", &search,
462 "imagemenuitem_quit", &quit,
463 "treeview_who", &window->treeview_who,
464 "treeview_what", &window->treeview_what,
465 "treeview_when", &window->treeview_when,
466 "treeview_events", &window->treeview_events,
467 "notebook", &window->notebook,
468 "spinner", &window->spinner,
472 empathy_builder_connect (gui, window,
473 "log_window", "destroy", log_window_destroy_cb,
474 "toolbutton_profile", "clicked", toolbutton_profile_clicked,
475 "toolbutton_chat", "clicked", toolbutton_chat_clicked,
476 "toolbutton_call", "clicked", toolbutton_av_clicked,
477 "toolbutton_video", "clicked", toolbutton_av_clicked,
478 "imagemenuitem_delete", "activate", log_window_delete_menu_clicked_cb,
481 g_object_unref (gui);
483 g_object_add_weak_pointer (G_OBJECT (window->window),
484 (gpointer) &log_window);
486 g_signal_connect_swapped (quit, "activate",
487 G_CALLBACK (gtk_widget_destroy), window->window);
489 /* Account chooser for chats */
490 vbox = gtk_vbox_new (FALSE, 3);
492 window->account_chooser = empathy_account_chooser_new ();
493 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
494 empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
495 empathy_account_chooser_set_filter (account_chooser,
496 empathy_account_chooser_filter_has_logs, NULL);
497 empathy_account_chooser_set_all (account_chooser);
499 g_signal_connect (window->account_chooser, "changed",
500 G_CALLBACK (log_window_chats_accounts_changed_cb),
503 label = gtk_label_new (_("Show"));
505 gtk_box_pack_start (GTK_BOX (vbox),
506 window->account_chooser,
509 gtk_box_pack_start (GTK_BOX (vbox),
513 gtk_widget_show_all (vbox);
514 gtk_container_add (GTK_CONTAINER (accounts), vbox);
517 vbox = gtk_vbox_new (FALSE, 3);
519 window->search_entry = gtk_entry_new ();
520 gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
521 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_FIND);
522 gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
523 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
525 label = gtk_label_new (_("Search"));
527 gtk_box_pack_start (GTK_BOX (vbox),
528 window->search_entry,
531 gtk_box_pack_start (GTK_BOX (vbox),
535 gtk_widget_show_all (vbox);
536 gtk_container_add (GTK_CONTAINER (search), vbox);
538 g_signal_connect (window->search_entry, "changed",
539 G_CALLBACK (log_window_search_entry_changed_cb),
542 g_signal_connect (window->search_entry, "activate",
543 G_CALLBACK (log_window_search_entry_activate_cb),
546 g_signal_connect (window->search_entry, "icon-press",
547 G_CALLBACK (log_window_search_entry_icon_pressed_cb),
551 log_window_events_setup (window);
552 log_window_who_setup (window);
553 log_window_what_setup (window);
554 log_window_when_setup (window);
556 log_window_who_populate (window);
558 if (account != NULL && chat_id != NULL)
559 select_account_once_ready (window, account, chat_id, is_chatroom);
562 gtk_window_set_transient_for (GTK_WINDOW (window->window),
563 GTK_WINDOW (parent));
565 gtk_widget_show (window->window);
567 return window->window;
571 log_window_destroy_cb (GtkWidget *widget,
572 EmpathyLogWindow *window)
574 if (window->source != 0)
575 g_source_remove (window->source);
577 g_free (window->last_find);
578 _tpl_action_chain_free (window->chain);
579 g_object_unref (window->log_manager);
580 tp_clear_object (&window->selected_account);
581 g_free (window->selected_chat_id);
587 account_equal (TpAccount *a,
590 return g_str_equal (tp_proxy_get_object_path (a),
591 tp_proxy_get_object_path (b));
595 entity_equal (TplEntity *a,
598 return g_str_equal (tpl_entity_get_identifier (a),
599 tpl_entity_get_identifier (b));
603 is_same_confroom (TplEvent *e1,
606 TplEntity *sender1 = tpl_event_get_sender (e1);
607 TplEntity *receiver1 = tpl_event_get_receiver (e1);
608 TplEntity *sender2 = tpl_event_get_sender (e2);
609 TplEntity *receiver2 = tpl_event_get_receiver (e2);
610 TplEntity *room1, *room2;
612 if (tpl_entity_get_entity_type (sender1) == TPL_ENTITY_ROOM)
614 else if (tpl_entity_get_entity_type (receiver1) == TPL_ENTITY_ROOM)
619 if (tpl_entity_get_entity_type (sender2) == TPL_ENTITY_ROOM)
621 else if (tpl_entity_get_entity_type (receiver2) == TPL_ENTITY_ROOM)
626 return g_str_equal (tpl_entity_get_identifier (room1),
627 tpl_entity_get_identifier (room1));
631 event_get_target (TplEvent *event)
633 TplEntity *sender = tpl_event_get_sender (event);
634 TplEntity *receiver = tpl_event_get_receiver (event);
636 if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
643 model_is_parent (GtkTreeModel *model,
647 TplEvent *stored_event;
650 gboolean found = FALSE;
653 if (gtk_tree_model_iter_parent (model, &parent, iter))
656 gtk_tree_model_get (model, iter,
657 COL_EVENTS_ACCOUNT, &account,
658 COL_EVENTS_TARGET, &target,
659 COL_EVENTS_EVENT, &stored_event,
662 if (G_OBJECT_TYPE (event) == G_OBJECT_TYPE (stored_event) &&
663 account_equal (account, tpl_event_get_account (event)) &&
664 (entity_equal (target, event_get_target (event)) ||
665 is_same_confroom (event, stored_event)))
670 gtk_tree_model_iter_nth_child (model, &child, iter,
671 gtk_tree_model_iter_n_children (model, iter) - 1);
673 gtk_tree_model_get (model, &child,
674 COL_EVENTS_TS, ×tamp,
677 if (ABS (tpl_event_get_timestamp (event) - timestamp) < MAX_GAP)
679 /* The gap is smaller than 30 min */
684 g_object_unref (stored_event);
685 g_object_unref (account);
686 g_object_unref (target);
692 get_contact_alias_for_message (EmpathyMessage *message)
694 EmpathyContact *sender, *receiver;
696 sender = empathy_message_get_sender (message);
697 receiver = empathy_message_get_receiver (message);
699 if (empathy_contact_is_user (sender))
700 return empathy_contact_get_alias (receiver);
702 return empathy_contact_get_alias (sender);
706 get_parent_iter_for_message (TplEvent *event,
707 EmpathyMessage *message,
713 gboolean parent_found = FALSE;
716 store = log_window->store_events;
717 model = GTK_TREE_MODEL (store);
719 for (next = gtk_tree_model_get_iter_first (model, &iter);
721 next = gtk_tree_model_iter_next (model, &iter))
723 if ((parent_found = model_is_parent (model, &iter, event)))
734 gchar *body, *pretty_date;
736 date = g_date_time_new_from_unix_utc (
737 tpl_event_get_timestamp (event));
739 pretty_date = g_date_time_format (date,
740 C_("A date with the time", "%A, %e %B %Y %X"));
742 body = g_strdup_printf (_("Chat with %s"),
743 get_contact_alias_for_message (message));
745 gtk_tree_store_append (store, &iter, NULL);
746 gtk_tree_store_set (store, &iter,
747 COL_EVENTS_TS, tpl_event_get_timestamp (event),
748 COL_EVENTS_PRETTY_DATE, pretty_date,
749 COL_EVENTS_TEXT, body,
750 COL_EVENTS_ICON, "stock_text_justify",
751 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
752 COL_EVENTS_TARGET, event_get_target (event),
753 COL_EVENTS_EVENT, event,
759 g_free (pretty_date);
760 g_date_time_unref (date);
765 get_icon_for_event (TplEvent *event)
767 const gchar *icon = NULL;
769 if (TPL_IS_CALL_EVENT (event))
771 TplCallEvent *call = TPL_CALL_EVENT (event);
772 TplCallEndReason reason = tpl_call_event_get_end_reason (call);
773 TplEntity *sender = tpl_event_get_sender (event);
774 TplEntity *receiver = tpl_event_get_receiver (event);
776 if (reason == TPL_CALL_END_REASON_NO_ANSWER)
777 icon = EMPATHY_IMAGE_CALL_MISSED;
778 else if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
779 icon = EMPATHY_IMAGE_CALL_OUTGOING;
780 else if (tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
781 icon = EMPATHY_IMAGE_CALL_INCOMING;
788 log_window_append_chat_message (TplEvent *event,
789 EmpathyMessage *message)
791 GtkTreeStore *store = log_window->store_events;
792 GtkTreeIter iter, parent;
793 gchar *pretty_date, *body;
796 date = g_date_time_new_from_unix_utc (
797 tpl_event_get_timestamp (event));
799 pretty_date = g_date_time_format (date, "%X");
801 get_parent_iter_for_message (event, message, &parent);
803 if (tpl_text_event_get_message_type (TPL_TEXT_EVENT (event))
804 == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION)
806 body = g_strdup_printf ("* %s %s",
807 tpl_entity_get_alias (tpl_event_get_sender (event)),
808 empathy_message_get_body (message));
812 body = g_strdup_printf (
813 C_("First is a contact, second is what was said", "%s: %s"),
814 tpl_entity_get_alias (tpl_event_get_sender (event)),
815 empathy_message_get_body (message));
818 gtk_tree_store_append (store, &iter, &parent);
819 gtk_tree_store_set (store, &iter,
820 COL_EVENTS_TS, tpl_event_get_timestamp (event),
821 COL_EVENTS_PRETTY_DATE, pretty_date,
822 COL_EVENTS_TEXT, body,
823 COL_EVENTS_ICON, get_icon_for_event (event),
824 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
825 COL_EVENTS_TARGET, event_get_target (event),
826 COL_EVENTS_EVENT, event,
830 g_free (pretty_date);
831 g_date_time_unref (date);
835 log_window_append_call (TplEvent *event,
836 EmpathyMessage *message)
838 TplCallEvent *call = TPL_CALL_EVENT (event);
839 GtkTreeStore *store = log_window->store_events;
840 GtkTreeIter iter, child;
841 gchar *pretty_date, *duration, *finished;
842 GDateTime *started_date, *finished_date;
845 started_date = g_date_time_new_from_unix_utc (
846 tpl_event_get_timestamp (event));
848 pretty_date = g_date_time_format (started_date,
849 C_("A date with the time", "%A, %e %B %Y %X"));
851 gtk_tree_store_append (store, &iter, NULL);
852 gtk_tree_store_set (store, &iter,
853 COL_EVENTS_TS, tpl_event_get_timestamp (event),
854 COL_EVENTS_PRETTY_DATE, pretty_date,
855 COL_EVENTS_TEXT, empathy_message_get_body (message),
856 COL_EVENTS_ICON, get_icon_for_event (event),
857 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
858 COL_EVENTS_TARGET, event_get_target (event),
859 COL_EVENTS_EVENT, event,
862 if (tpl_call_event_get_end_reason (call) != TPL_CALL_END_REASON_NO_ANSWER)
866 span = tpl_call_event_get_duration (TPL_CALL_EVENT (event));
868 duration = g_strdup_printf (_("%" G_GINT64_FORMAT " seconds"), span);
870 duration = g_strdup_printf (_("%" G_GINT64_FORMAT " minutes"),
873 finished_date = g_date_time_add (started_date, -span);
874 finished = g_date_time_format (finished_date, "%X");
875 g_date_time_unref (finished_date);
877 body = g_strdup_printf (_("Call took %s, ended at %s"),
883 gtk_tree_store_append (store, &child, &iter);
884 gtk_tree_store_set (store, &child,
885 COL_EVENTS_TS, tpl_event_get_timestamp (event),
886 COL_EVENTS_TEXT, body,
887 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
888 COL_EVENTS_TARGET, event_get_target (event),
889 COL_EVENTS_EVENT, event,
895 g_free (pretty_date);
896 g_date_time_unref (started_date);
900 log_window_append_message (TplEvent *event,
901 EmpathyMessage *message)
903 if (TPL_IS_TEXT_EVENT (event))
904 log_window_append_chat_message (event, message);
905 else if (TPL_IS_CALL_EVENT (event))
906 log_window_append_call (event, message);
908 DEBUG ("Message type not handled");
912 add_all_accounts_and_entities (GList **accounts,
919 view = GTK_TREE_VIEW (log_window->treeview_who);
920 model = gtk_tree_view_get_model (view);
922 if (!gtk_tree_model_get_iter_first (model, &iter))
931 gtk_tree_model_get (model, &iter,
932 COL_WHO_ACCOUNT, &account,
933 COL_WHO_TARGET, &entity,
937 if (type != COL_TYPE_NORMAL)
940 if (accounts != NULL)
941 *accounts = g_list_append (*accounts, account);
943 if (entities != NULL)
944 *entities = g_list_append (*entities, entity);
946 while (gtk_tree_model_iter_next (model, &iter));
950 log_window_get_selected (EmpathyLogWindow *window,
954 TplEventTypeMask *event_mask,
955 EventSubtype *subtype)
959 GtkTreeSelection *selection;
961 TplEventTypeMask ev = 0;
966 view = GTK_TREE_VIEW (window->treeview_who);
967 model = gtk_tree_view_get_model (view);
968 selection = gtk_tree_view_get_selection (view);
970 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
974 if (accounts != NULL)
976 if (entities != NULL)
979 for (l = paths; l != NULL; l = l->next)
981 GtkTreePath *path = l->data;
985 gtk_tree_model_get_iter (model, &iter, path);
986 gtk_tree_model_get (model, &iter,
987 COL_WHO_ACCOUNT, &account,
988 COL_WHO_TARGET, &entity,
992 if (type == COL_TYPE_ANY)
994 if (accounts != NULL || entities != NULL)
995 add_all_accounts_and_entities (accounts, entities);
999 if (accounts != NULL)
1000 *accounts = g_list_append (*accounts, g_object_ref (account));
1002 if (entities != NULL)
1003 *entities = g_list_append (*entities, g_object_ref (entity));
1005 g_object_unref (account);
1006 g_object_unref (entity);
1008 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1010 view = GTK_TREE_VIEW (window->treeview_what);
1011 model = gtk_tree_view_get_model (view);
1012 selection = gtk_tree_view_get_selection (view);
1014 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1015 for (l = paths; l != NULL; l = l->next)
1017 GtkTreePath *path = l->data;
1018 TplEventTypeMask mask;
1019 EventSubtype submask;
1021 gtk_tree_model_get_iter (model, &iter, path);
1022 gtk_tree_model_get (model, &iter,
1023 COL_WHAT_TYPE, &mask,
1024 COL_WHAT_SUBTYPE, &submask,
1030 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1032 view = GTK_TREE_VIEW (window->treeview_when);
1033 model = gtk_tree_view_get_model (view);
1034 selection = gtk_tree_view_get_selection (view);
1040 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1041 for (l = paths; l != NULL; l = l->next)
1043 GtkTreePath *path = l->data;
1046 gtk_tree_model_get_iter (model, &iter, path);
1047 gtk_tree_model_get (model, &iter,
1048 COL_WHEN_DATE, &date,
1051 *dates = g_list_append (*dates, date);
1053 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1056 if (event_mask != NULL)
1059 if (subtype != NULL)
1066 model_has_entity (GtkTreeModel *model,
1071 TplLogSearchHit *hit = data;
1074 gboolean ret = FALSE;
1076 gtk_tree_model_get (model, iter,
1078 COL_WHO_ACCOUNT, &a,
1081 if (e != NULL && entity_equal (hit->target, e) &&
1082 a != NULL && account_equal (hit->account, a))
1084 ret = has_element = TRUE;
1087 tp_clear_object (&e);
1088 tp_clear_object (&a);
1094 model_has_date (GtkTreeModel *model,
1102 gtk_tree_model_get (model, iter,
1106 if (!g_date_compare (date, d))
1116 get_events_for_date (TplActionChain *chain, gpointer user_data);
1119 populate_events_from_search_hits (GList *accounts,
1123 TplEventTypeMask event_mask;
1124 EventSubtype subtype;
1127 gboolean is_anytime = FALSE;
1129 if (!log_window_get_selected (log_window,
1130 NULL, NULL, NULL, &event_mask, &subtype))
1133 anytime = g_date_new_dmy (2, 1, -1);
1134 if (g_list_find_custom (dates, anytime, (GCompareFunc) g_date_compare))
1137 for (l = log_window->hits; l != NULL; l = l->next)
1139 TplLogSearchHit *hit = l->data;
1141 gboolean found = FALSE;
1143 /* Protect against invalid data (corrupt or old log files). */
1144 if (hit->account == NULL || hit->target == NULL)
1147 for (acc = accounts, targ = targets;
1148 acc != NULL && targ != NULL && !found;
1149 acc = acc->next, targ = targ->next)
1151 TpAccount *account = acc->data;
1152 TplEntity *target = targ->data;
1154 if (account_equal (hit->account, account) &&
1155 entity_equal (hit->target, target))
1163 g_list_find_custom (dates, hit->date, (GCompareFunc) g_date_compare)
1168 ctx = ctx_new (log_window, hit->account, hit->target, hit->date,
1169 event_mask, subtype, log_window->count);
1170 _tpl_action_chain_append (log_window->chain,
1171 get_events_for_date, ctx);
1175 _tpl_action_chain_start (log_window->chain);
1177 g_date_free (anytime);
1181 format_date_for_display (GDate *date)
1187 /* g_date_strftime sucks */
1189 now = g_date_new ();
1190 g_date_set_time_t (now, time (NULL));
1192 days_elapsed = g_date_days_between (date, now);
1194 if (days_elapsed < 0)
1198 else if (days_elapsed == 0)
1200 text = g_strdup (_("Today"));
1202 else if (days_elapsed == 1)
1204 text = g_strdup (_("Yesterday"));
1210 dt = g_date_time_new_utc (g_date_get_year (date),
1211 g_date_get_month (date), g_date_get_day (date),
1214 if (days_elapsed <= 7)
1215 text = g_date_time_format (dt, "%A");
1217 text = g_date_time_format (dt,
1218 C_("A date such as '23 May 2010', "
1219 "%e is the day, %B the month and %Y the year",
1222 g_date_time_unref (dt);
1231 populate_dates_from_search_hits (GList *accounts,
1236 GtkTreeModel *model;
1237 GtkListStore *store;
1238 GtkTreeSelection *selection;
1241 if (log_window == NULL)
1244 view = GTK_TREE_VIEW (log_window->treeview_when);
1245 model = gtk_tree_view_get_model (view);
1246 store = GTK_LIST_STORE (model);
1247 selection = gtk_tree_view_get_selection (view);
1249 for (l = log_window->hits; l != NULL; l = l->next)
1251 TplLogSearchHit *hit = l->data;
1253 gboolean found = FALSE;
1255 /* Protect against invalid data (corrupt or old log files). */
1256 if (hit->account == NULL || hit->target == NULL)
1259 for (acc = accounts, targ = targets;
1260 acc != NULL && targ != NULL && !found;
1261 acc = acc->next, targ = targ->next)
1263 TpAccount *account = acc->data;
1264 TplEntity *target = targ->data;
1266 if (account_equal (hit->account, account) &&
1267 entity_equal (hit->target, target))
1274 /* Add the date if it's not already there */
1275 has_element = FALSE;
1276 gtk_tree_model_foreach (model, model_has_date, hit->date);
1279 gchar *text = format_date_for_display (hit->date);
1281 gtk_list_store_append (store, &iter);
1282 gtk_list_store_set (store, &iter,
1283 COL_WHEN_DATE, hit->date,
1284 COL_WHEN_TEXT, text,
1285 COL_WHEN_ICON, CALENDAR_ICON,
1290 if (gtk_tree_model_get_iter_first (model, &iter))
1292 gtk_list_store_prepend (store, &iter);
1293 gtk_list_store_set (store, &iter,
1294 COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
1295 COL_WHEN_TEXT, "separator",
1298 gtk_list_store_prepend (store, &iter);
1299 gtk_list_store_set (store, &iter,
1300 COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
1301 COL_WHEN_TEXT, _("Anytime"),
1304 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 2))
1305 gtk_tree_selection_select_iter (selection, &iter);
1310 populate_entities_from_search_hits (void)
1312 EmpathyAccountChooser *account_chooser;
1315 GtkTreeModel *model;
1317 GtkListStore *store;
1320 view = GTK_TREE_VIEW (log_window->treeview_who);
1321 model = gtk_tree_view_get_model (view);
1322 store = GTK_LIST_STORE (model);
1324 gtk_list_store_clear (store);
1326 account_chooser = EMPATHY_ACCOUNT_CHOOSER (log_window->account_chooser);
1327 account = empathy_account_chooser_get_account (account_chooser);
1329 for (l = log_window->hits; l; l = l->next)
1331 TplLogSearchHit *hit = l->data;
1333 /* Protect against invalid data (corrupt or old log files). */
1334 if (hit->account == NULL || hit->target == NULL)
1337 /* Filter based on the selected account */
1338 if (account != NULL && !account_equal (account, hit->account))
1341 /* Add the entity if it's not already there */
1342 has_element = FALSE;
1343 gtk_tree_model_foreach (model, model_has_entity, hit);
1346 TplEntityType type = tpl_entity_get_entity_type (hit->target);
1347 gboolean room = type == TPL_ENTITY_ROOM;
1349 gtk_list_store_append (store, &iter);
1350 gtk_list_store_set (store, &iter,
1351 COL_WHO_TYPE, COL_TYPE_NORMAL,
1352 COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
1353 : EMPATHY_IMAGE_AVATAR_DEFAULT,
1354 COL_WHO_NAME, tpl_entity_get_alias (hit->target),
1355 COL_WHO_ACCOUNT, hit->account,
1356 COL_WHO_TARGET, hit->target,
1361 if (gtk_tree_model_get_iter_first (model, &iter))
1363 gtk_list_store_prepend (store, &iter);
1364 gtk_list_store_set (store, &iter,
1365 COL_WHO_TYPE, COL_TYPE_SEPARATOR,
1366 COL_WHO_NAME, "separator",
1369 gtk_list_store_prepend (store, &iter);
1370 gtk_list_store_set (store, &iter,
1371 COL_WHO_TYPE, COL_TYPE_ANY,
1372 COL_WHO_NAME, _("Anyone"),
1376 /* FIXME: select old entity if still available */
1380 log_manager_searched_new_cb (GObject *manager,
1381 GAsyncResult *result,
1386 GtkTreeSelection *selection;
1387 GError *error = NULL;
1389 if (log_window == NULL)
1392 if (!tpl_log_manager_search_finish (TPL_LOG_MANAGER (manager),
1393 result, &hits, &error))
1395 DEBUG ("%s. Aborting", error->message);
1396 g_error_free (error);
1400 tp_clear_pointer (&log_window->hits, tpl_log_manager_search_free);
1401 log_window->hits = hits;
1403 populate_entities_from_search_hits ();
1405 view = GTK_TREE_VIEW (log_window->treeview_when);
1406 selection = gtk_tree_view_get_selection (view);
1408 g_signal_handlers_unblock_by_func (selection,
1409 log_window_when_changed_cb,
1414 log_window_find_populate (EmpathyLogWindow *window,
1415 const gchar *search_criteria)
1418 GtkTreeModel *model;
1419 GtkTreeSelection *selection;
1420 GtkListStore *store;
1422 gtk_tree_store_clear (window->store_events);
1424 view = GTK_TREE_VIEW (window->treeview_who);
1425 model = gtk_tree_view_get_model (view);
1426 store = GTK_LIST_STORE (model);
1428 gtk_list_store_clear (store);
1430 view = GTK_TREE_VIEW (window->treeview_when);
1431 model = gtk_tree_view_get_model (view);
1432 store = GTK_LIST_STORE (model);
1433 selection = gtk_tree_view_get_selection (view);
1435 gtk_list_store_clear (store);
1437 if (EMP_STR_EMPTY (search_criteria))
1439 tp_clear_pointer (&window->hits, tpl_log_manager_search_free);
1440 log_window_who_populate (window);
1444 g_signal_handlers_block_by_func (selection,
1445 log_window_when_changed_cb,
1448 tpl_log_manager_search_async (window->log_manager,
1449 search_criteria, TPL_EVENT_MASK_ANY,
1450 log_manager_searched_new_cb, NULL);
1454 start_find_search (EmpathyLogWindow *window)
1458 str = gtk_entry_get_text (GTK_ENTRY (window->search_entry));
1460 /* Don't find the same crap again */
1461 if (window->last_find && !tp_strdiff (window->last_find, str))
1464 g_free (window->last_find);
1465 window->last_find = g_strdup (str);
1467 log_window_find_populate (window, str);
1473 log_window_search_entry_changed_cb (GtkWidget *entry,
1474 EmpathyLogWindow *window)
1476 if (window->source != 0)
1477 g_source_remove (window->source);
1478 window->source = g_timeout_add (500, (GSourceFunc) start_find_search,
1483 log_window_search_entry_activate_cb (GtkWidget *entry,
1484 EmpathyLogWindow *self)
1486 start_find_search (self);
1490 log_window_search_entry_icon_pressed_cb (GtkEntry *entry,
1491 GtkEntryIconPosition icon_pos,
1495 if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
1498 gtk_entry_buffer_set_text (gtk_entry_get_buffer (entry),
1503 log_window_update_buttons_sensitivity (EmpathyLogWindow *window,
1504 GtkTreeModel *model,
1505 GtkTreeSelection *selection)
1507 EmpathyContact *contact;
1508 EmpathyCapabilities capabilities;
1514 gboolean profile, chat, call, video;
1516 profile = chat = call = video = FALSE;
1518 if (!gtk_tree_model_get_iter_first (model, &iter))
1521 if (gtk_tree_selection_count_selected_rows (selection) != 1)
1524 if (gtk_tree_selection_iter_is_selected (selection, &iter))
1527 paths = gtk_tree_selection_get_selected_rows (selection, &model);
1528 g_return_if_fail (paths != NULL);
1531 gtk_tree_model_get_iter (model, &iter, path);
1532 gtk_tree_model_get (model, &iter,
1533 COL_WHO_ACCOUNT, &account,
1534 COL_WHO_TARGET, &target,
1537 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1539 contact = empathy_contact_from_tpl_contact (account, target);
1541 g_object_unref (account);
1542 g_object_unref (target);
1544 capabilities = empathy_contact_get_capabilities (contact);
1546 profile = chat = TRUE;
1547 call = capabilities & EMPATHY_CAPABILITIES_AUDIO;
1548 video = capabilities & EMPATHY_CAPABILITIES_VIDEO;
1551 gtk_widget_set_sensitive (window->button_profile, profile);
1552 gtk_widget_set_sensitive (window->button_chat, chat);
1553 gtk_widget_set_sensitive (window->button_call, call);
1554 gtk_widget_set_sensitive (window->button_video, video);
1558 log_window_who_changed_cb (GtkTreeSelection *selection,
1559 EmpathyLogWindow *window)
1562 GtkTreeModel *model;
1565 DEBUG ("log_window_who_changed_cb");
1567 view = gtk_tree_selection_get_tree_view (selection);
1568 model = gtk_tree_view_get_model (view);
1570 if (gtk_tree_model_get_iter_first (model, &iter))
1572 /* If 'Anyone' is selected, everything else should be deselected */
1573 if (gtk_tree_selection_iter_is_selected (selection, &iter))
1575 g_signal_handlers_block_by_func (selection,
1576 log_window_who_changed_cb,
1579 gtk_tree_selection_unselect_all (selection);
1580 gtk_tree_selection_select_iter (selection, &iter);
1582 g_signal_handlers_unblock_by_func (selection,
1583 log_window_who_changed_cb,
1588 log_window_update_buttons_sensitivity (window, model, selection);
1590 /* The contact changed, so the dates need to be updated */
1591 log_window_chats_get_messages (window, TRUE);
1595 log_manager_got_entities_cb (GObject *manager,
1596 GAsyncResult *result,
1599 Ctx *ctx = user_data;
1603 GtkTreeModel *model;
1604 GtkTreeSelection *selection;
1605 GtkListStore *store;
1607 GError *error = NULL;
1608 gboolean select_account = FALSE;
1610 if (log_window == NULL)
1613 if (log_window->count != ctx->count)
1616 if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
1617 result, &entities, &error))
1619 DEBUG ("%s. Aborting", error->message);
1620 g_error_free (error);
1624 view = GTK_TREE_VIEW (ctx->window->treeview_who);
1625 model = gtk_tree_view_get_model (view);
1626 selection = gtk_tree_view_get_selection (view);
1627 store = GTK_LIST_STORE (model);
1629 /* Block signals to stop the logs being retrieved prematurely */
1630 g_signal_handlers_block_by_func (selection,
1631 log_window_who_changed_cb, ctx->window);
1633 for (l = entities; l; l = l->next)
1635 TplEntity *entity = TPL_ENTITY (l->data);
1636 TplEntityType type = tpl_entity_get_entity_type (entity);
1637 gboolean room = type == TPL_ENTITY_ROOM;
1639 gtk_list_store_append (store, &iter);
1640 gtk_list_store_set (store, &iter,
1641 COL_WHO_TYPE, COL_TYPE_NORMAL,
1642 COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
1643 : EMPATHY_IMAGE_AVATAR_DEFAULT,
1644 COL_WHO_NAME, tpl_entity_get_alias (entity),
1645 COL_WHO_ACCOUNT, ctx->account,
1646 COL_WHO_TARGET, entity,
1649 if (ctx->window->selected_account != NULL &&
1650 !tp_strdiff (tp_proxy_get_object_path (ctx->account),
1651 tp_proxy_get_object_path (ctx->window->selected_account)))
1652 select_account = TRUE;
1654 g_list_free_full (entities, g_object_unref);
1656 if (gtk_tree_model_get_iter_first (model, &iter))
1660 gtk_tree_model_get (model, &iter,
1661 COL_WHO_TYPE, &type,
1664 if (type != COL_TYPE_ANY)
1666 gtk_list_store_prepend (store, &iter);
1667 gtk_list_store_set (store, &iter,
1668 COL_WHO_TYPE, COL_TYPE_SEPARATOR,
1669 COL_WHO_NAME, "separator",
1672 gtk_list_store_prepend (store, &iter);
1673 gtk_list_store_set (store, &iter,
1674 COL_WHO_TYPE, COL_TYPE_ANY,
1675 COL_WHO_NAME, _("Anyone"),
1680 /* Unblock signals */
1681 g_signal_handlers_unblock_by_func (selection,
1682 log_window_who_changed_cb,
1685 /* We display the selected account if we populate the model with chats from
1688 log_window_chats_set_selected (ctx->window);
1691 _tpl_action_chain_continue (log_window->chain);
1696 get_entities_for_account (TplActionChain *chain, gpointer user_data)
1698 Ctx *ctx = user_data;
1700 tpl_log_manager_get_entities_async (ctx->window->log_manager, ctx->account,
1701 log_manager_got_entities_cb, ctx);
1705 select_first_entity (TplActionChain *chain, gpointer user_data)
1708 GtkTreeModel *model;
1709 GtkTreeSelection *selection;
1712 view = GTK_TREE_VIEW (log_window->treeview_who);
1713 model = gtk_tree_view_get_model (view);
1714 selection = gtk_tree_view_get_selection (view);
1716 if (gtk_tree_model_get_iter_first (model, &iter))
1717 gtk_tree_selection_select_iter (selection, &iter);
1719 _tpl_action_chain_continue (log_window->chain);
1723 log_window_who_populate (EmpathyLogWindow *window)
1725 EmpathyAccountChooser *account_chooser;
1727 gboolean all_accounts;
1729 GtkTreeModel *model;
1730 GtkTreeSelection *selection;
1731 GtkListStore *store;
1734 if (window->hits != NULL)
1736 populate_entities_from_search_hits ();
1740 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
1741 account = empathy_account_chooser_dup_account (account_chooser);
1742 all_accounts = empathy_account_chooser_has_all_selected (account_chooser);
1744 view = GTK_TREE_VIEW (window->treeview_who);
1745 model = gtk_tree_view_get_model (view);
1746 selection = gtk_tree_view_get_selection (view);
1747 store = GTK_LIST_STORE (model);
1749 /* Block signals to stop the logs being retrieved prematurely */
1750 g_signal_handlers_block_by_func (selection,
1751 log_window_who_changed_cb,
1754 gtk_list_store_clear (store);
1756 /* Unblock signals */
1757 g_signal_handlers_unblock_by_func (selection,
1758 log_window_who_changed_cb,
1761 _tpl_action_chain_clear (window->chain);
1764 if (!all_accounts && account == NULL)
1768 else if (!all_accounts)
1770 ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
1771 _tpl_action_chain_append (window->chain, get_entities_for_account, ctx);
1775 TpAccountManager *manager;
1776 GList *accounts, *l;
1778 manager = empathy_account_chooser_get_account_manager (account_chooser);
1779 accounts = tp_account_manager_get_valid_accounts (manager);
1781 for (l = accounts; l != NULL; l = l->next)
1785 ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
1786 _tpl_action_chain_append (window->chain,
1787 get_entities_for_account, ctx);
1790 g_list_free (accounts);
1792 _tpl_action_chain_append (window->chain, select_first_entity, NULL);
1793 _tpl_action_chain_start (window->chain);
1797 sort_by_name (GtkTreeModel *model,
1802 gchar *name1, *name2;
1806 gtk_tree_model_get (model, a,
1807 COL_WHO_TYPE, &type1,
1808 COL_WHO_NAME, &name1,
1811 gtk_tree_model_get (model, b,
1812 COL_WHO_TYPE, &type2,
1813 COL_WHO_NAME, &name2,
1816 if (type1 == COL_TYPE_ANY)
1818 else if (type2 == COL_TYPE_ANY)
1820 else if (type1 == COL_TYPE_SEPARATOR)
1822 else if (type2 == COL_TYPE_SEPARATOR)
1825 ret = g_strcmp0 (name1, name2);
1834 who_row_is_separator (GtkTreeModel *model,
1840 gtk_tree_model_get (model, iter,
1841 COL_WHO_TYPE, &type,
1844 return (type == COL_TYPE_SEPARATOR);
1848 log_window_events_setup (EmpathyLogWindow *window)
1851 GtkTreeModel *model;
1852 GtkTreeSelection *selection;
1853 GtkTreeSortable *sortable;
1854 GtkTreeViewColumn *column;
1855 GtkTreeStore *store;
1856 GtkCellRenderer *cell;
1858 view = GTK_TREE_VIEW (window->treeview_events);
1859 selection = gtk_tree_view_get_selection (view);
1862 window->store_events = store = gtk_tree_store_new (COL_EVENTS_COUNT,
1863 G_TYPE_INT, /* type */
1864 G_TYPE_INT64, /* timestamp */
1865 G_TYPE_STRING, /* stringified date */
1866 G_TYPE_STRING, /* icon */
1867 G_TYPE_STRING, /* name */
1868 TP_TYPE_ACCOUNT, /* account */
1869 TPL_TYPE_ENTITY, /* target */
1870 TPL_TYPE_EVENT); /* event */
1872 model = GTK_TREE_MODEL (store);
1873 sortable = GTK_TREE_SORTABLE (store);
1875 gtk_tree_view_set_model (view, model);
1878 column = gtk_tree_view_column_new ();
1880 cell = gtk_cell_renderer_pixbuf_new ();
1881 gtk_tree_view_column_pack_start (column, cell, FALSE);
1882 gtk_tree_view_column_add_attribute (column, cell,
1883 "icon-name", COL_EVENTS_ICON);
1885 cell = gtk_cell_renderer_text_new ();
1886 gtk_tree_view_column_pack_start (column, cell, TRUE);
1887 gtk_tree_view_column_add_attribute (column, cell,
1888 "text", COL_EVENTS_TEXT);
1890 cell = gtk_cell_renderer_text_new ();
1891 g_object_set (cell, "xalign", 1.0, NULL);
1892 gtk_tree_view_column_pack_end (column, cell, FALSE);
1893 gtk_tree_view_column_add_attribute (column, cell,
1894 "text", COL_EVENTS_PRETTY_DATE);
1896 gtk_tree_view_append_column (view, column);
1898 /* set up treeview properties */
1899 gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
1900 gtk_tree_view_set_headers_visible (view, FALSE);
1902 gtk_tree_sortable_set_sort_column_id (sortable,
1904 GTK_SORT_ASCENDING);
1906 g_object_unref (store);
1910 log_window_who_setup (EmpathyLogWindow *window)
1913 GtkTreeModel *model;
1914 GtkTreeSelection *selection;
1915 GtkTreeSortable *sortable;
1916 GtkTreeViewColumn *column;
1917 GtkListStore *store;
1918 GtkCellRenderer *cell;
1920 view = GTK_TREE_VIEW (window->treeview_who);
1921 selection = gtk_tree_view_get_selection (view);
1924 store = gtk_list_store_new (COL_WHO_COUNT,
1925 G_TYPE_INT, /* type */
1926 G_TYPE_STRING, /* icon */
1927 G_TYPE_STRING, /* name */
1928 TP_TYPE_ACCOUNT, /* account */
1929 TPL_TYPE_ENTITY); /* target */
1931 model = GTK_TREE_MODEL (store);
1932 sortable = GTK_TREE_SORTABLE (store);
1934 gtk_tree_view_set_model (view, model);
1937 column = gtk_tree_view_column_new ();
1938 gtk_tree_view_column_set_title (column, _("Who"));
1940 cell = gtk_cell_renderer_pixbuf_new ();
1941 gtk_tree_view_column_pack_start (column, cell, FALSE);
1942 gtk_tree_view_column_add_attribute (column, cell,
1946 cell = gtk_cell_renderer_text_new ();
1947 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1948 gtk_tree_view_column_pack_start (column, cell, TRUE);
1949 gtk_tree_view_column_add_attribute (column, cell,
1953 gtk_tree_view_append_column (view, column);
1955 /* set up treeview properties */
1956 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1957 gtk_tree_view_set_row_separator_func (view, who_row_is_separator,
1960 gtk_tree_sortable_set_sort_column_id (sortable,
1962 GTK_SORT_ASCENDING);
1963 gtk_tree_sortable_set_sort_func (sortable,
1964 COL_WHO_NAME, sort_by_name,
1967 gtk_tree_view_set_search_column (view, COL_WHO_NAME);
1969 /* set up signals */
1970 g_signal_connect (selection, "changed",
1971 G_CALLBACK (log_window_who_changed_cb), window);
1973 g_object_unref (store);
1977 log_window_chats_accounts_changed_cb (GtkWidget *combobox,
1978 EmpathyLogWindow *window)
1980 /* Clear all current messages shown in the textview */
1981 gtk_tree_store_clear (window->store_events);
1983 log_window_who_populate (window);
1987 log_window_chats_set_selected (EmpathyLogWindow *window)
1990 GtkTreeModel *model;
1991 GtkTreeSelection *selection;
1996 view = GTK_TREE_VIEW (window->treeview_who);
1997 model = gtk_tree_view_get_model (view);
1998 selection = gtk_tree_view_get_selection (view);
2000 for (next = gtk_tree_model_get_iter_first (model, &iter);
2002 next = gtk_tree_model_iter_next (model, &iter))
2004 TpAccount *this_account;
2005 TplEntity *this_target;
2006 const gchar *this_chat_id;
2007 gboolean this_is_chatroom;
2010 gtk_tree_model_get (model, &iter,
2011 COL_WHO_TYPE, &this_type,
2012 COL_WHO_ACCOUNT, &this_account,
2013 COL_WHO_TARGET, &this_target,
2016 if (this_type != COL_TYPE_NORMAL)
2019 this_chat_id = tpl_entity_get_identifier (this_target);
2020 this_is_chatroom = tpl_entity_get_entity_type (this_target)
2023 if (this_account == window->selected_account &&
2024 !tp_strdiff (this_chat_id, window->selected_chat_id) &&
2025 this_is_chatroom == window->selected_is_chatroom)
2027 gtk_tree_selection_select_iter (selection, &iter);
2028 path = gtk_tree_model_get_path (model, &iter);
2029 gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
2030 gtk_tree_path_free (path);
2031 g_object_unref (this_account);
2032 g_object_unref (this_target);
2036 g_object_unref (this_account);
2037 g_object_unref (this_target);
2040 tp_clear_object (&window->selected_account);
2041 tp_clear_pointer (&window->selected_chat_id, g_free);
2045 sort_by_date (GtkTreeModel *model,
2050 GDate *date1, *date2;
2052 gtk_tree_model_get (model, a,
2053 COL_WHEN_DATE, &date1,
2056 gtk_tree_model_get (model, b,
2057 COL_WHEN_DATE, &date2,
2060 return g_date_compare (date1, date2);
2064 when_row_is_separator (GtkTreeModel *model,
2071 gtk_tree_model_get (model, iter,
2072 COL_WHEN_TEXT, &when,
2075 ret = g_str_equal (when, "separator");
2081 log_window_when_changed_cb (GtkTreeSelection *selection,
2082 EmpathyLogWindow *window)
2085 GtkTreeModel *model;
2088 DEBUG ("log_window_when_changed_cb");
2090 view = gtk_tree_selection_get_tree_view (selection);
2091 model = gtk_tree_view_get_model (view);
2093 /* If 'Anytime' is selected, everything else should be deselected */
2094 if (gtk_tree_model_get_iter_first (model, &iter))
2096 if (gtk_tree_selection_iter_is_selected (selection, &iter))
2098 g_signal_handlers_block_by_func (selection,
2099 log_window_when_changed_cb,
2102 gtk_tree_selection_unselect_all (selection);
2103 gtk_tree_selection_select_iter (selection, &iter);
2105 g_signal_handlers_unblock_by_func (selection,
2106 log_window_when_changed_cb,
2111 log_window_chats_get_messages (window, FALSE);
2115 log_window_when_setup (EmpathyLogWindow *window)
2118 GtkTreeModel *model;
2119 GtkTreeSelection *selection;
2120 GtkTreeSortable *sortable;
2121 GtkTreeViewColumn *column;
2122 GtkListStore *store;
2123 GtkCellRenderer *cell;
2125 view = GTK_TREE_VIEW (window->treeview_when);
2126 selection = gtk_tree_view_get_selection (view);
2129 store = gtk_list_store_new (COL_WHEN_COUNT,
2130 G_TYPE_DATE, /* date */
2131 G_TYPE_STRING, /* stringified date */
2132 G_TYPE_STRING); /* icon */
2134 model = GTK_TREE_MODEL (store);
2135 sortable = GTK_TREE_SORTABLE (store);
2137 gtk_tree_view_set_model (view, model);
2140 column = gtk_tree_view_column_new ();
2141 gtk_tree_view_column_set_title (column, _("When"));
2143 cell = gtk_cell_renderer_pixbuf_new ();
2144 gtk_tree_view_column_pack_start (column, cell, FALSE);
2145 gtk_tree_view_column_add_attribute (column, cell,
2146 "icon-name", COL_WHEN_ICON);
2148 cell = gtk_cell_renderer_text_new ();
2149 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2150 gtk_tree_view_column_pack_start (column, cell, TRUE);
2151 gtk_tree_view_column_add_attribute (column, cell,
2155 gtk_tree_view_append_column (view, column);
2157 /* set up treeview properties */
2158 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2159 gtk_tree_view_set_row_separator_func (view, when_row_is_separator,
2161 gtk_tree_sortable_set_sort_column_id (sortable,
2163 GTK_SORT_DESCENDING);
2164 gtk_tree_sortable_set_sort_func (sortable,
2165 COL_WHEN_DATE, sort_by_date,
2168 gtk_tree_view_set_search_column (view, COL_WHEN_TEXT);
2170 /* set up signals */
2171 g_signal_connect (selection, "changed",
2172 G_CALLBACK (log_window_when_changed_cb),
2175 g_object_unref (store);
2179 what_row_is_separator (GtkTreeModel *model,
2185 gtk_tree_model_get (model, iter,
2186 COL_WHAT_TYPE, &type,
2189 return (type == WHAT_TYPE_SEPARATOR);
2193 log_window_what_changed_cb (GtkTreeSelection *selection,
2194 EmpathyLogWindow *window)
2197 GtkTreeModel *model;
2200 DEBUG ("log_window_what_changed_cb");
2202 view = gtk_tree_selection_get_tree_view (selection);
2203 model = gtk_tree_view_get_model (view);
2205 /* If 'Anything' is selected, everything else should be deselected */
2206 if (gtk_tree_model_get_iter_first (model, &iter))
2208 if (gtk_tree_selection_iter_is_selected (selection, &iter))
2210 g_signal_handlers_block_by_func (selection,
2211 log_window_what_changed_cb,
2214 gtk_tree_selection_unselect_all (selection);
2215 gtk_tree_selection_select_iter (selection, &iter);
2217 g_signal_handlers_unblock_by_func (selection,
2218 log_window_what_changed_cb,
2223 /* The dates need to be updated if we're not searching */
2224 log_window_chats_get_messages (window, window->hits == NULL);
2228 log_window_what_collapse_row_cb (GtkTreeView *tree_view,
2233 /* Reject collapsing */
2240 EventSubtype subtype;
2246 log_window_what_setup (EmpathyLogWindow *window)
2249 GtkTreeModel *model;
2250 GtkTreeSelection *selection;
2251 GtkTreeSortable *sortable;
2252 GtkTreeViewColumn *column;
2253 GtkTreeIter iter, parent;
2254 GtkTreeStore *store;
2255 GtkCellRenderer *cell;
2257 struct event events [] = {
2258 { TPL_EVENT_MASK_ANY, 0, NULL, _("Anything") },
2259 { WHAT_TYPE_SEPARATOR, 0, NULL, "separator" },
2260 { TPL_EVENT_MASK_TEXT, 0, "stock_text_justify", _("Text chats") },
2261 { TPL_EVENT_MASK_CALL, EVENT_CALL_ALL, "call-start", _("Calls") }
2263 struct event call_events [] = {
2264 { TPL_EVENT_MASK_CALL, EVENT_CALL_INCOMING, "call-start", _("Incoming calls") },
2265 { TPL_EVENT_MASK_CALL, EVENT_CALL_OUTGOING, "call-start", _("Outgoing calls") },
2266 { TPL_EVENT_MASK_CALL, EVENT_CALL_MISSED, "call-stop", _("Missed calls") }
2269 view = GTK_TREE_VIEW (window->treeview_what);
2270 selection = gtk_tree_view_get_selection (view);
2273 store = gtk_tree_store_new (COL_WHAT_COUNT,
2274 G_TYPE_INT, /* history type */
2275 G_TYPE_INT, /* history subtype */
2276 G_TYPE_STRING, /* stringified history type */
2277 G_TYPE_STRING); /* icon */
2279 model = GTK_TREE_MODEL (store);
2280 sortable = GTK_TREE_SORTABLE (store);
2282 gtk_tree_view_set_model (view, model);
2285 column = gtk_tree_view_column_new ();
2286 gtk_tree_view_column_set_title (column, _("What"));
2288 cell = gtk_cell_renderer_pixbuf_new ();
2289 gtk_tree_view_column_pack_start (column, cell, FALSE);
2290 gtk_tree_view_column_add_attribute (column, cell,
2291 "icon-name", COL_WHAT_ICON);
2293 cell = gtk_cell_renderer_text_new ();
2294 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2295 gtk_tree_view_column_pack_start (column, cell, TRUE);
2296 gtk_tree_view_column_add_attribute (column, cell,
2297 "text", COL_WHAT_TEXT);
2299 gtk_tree_view_append_column (view, column);
2300 gtk_tree_view_set_search_column (view, COL_WHAT_TEXT);
2302 /* set up treeview properties */
2303 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2304 gtk_tree_view_set_show_expanders (view, FALSE);
2305 gtk_tree_view_set_level_indentation (view, 12);
2306 gtk_tree_view_expand_all (view);
2307 gtk_tree_view_set_row_separator_func (view, what_row_is_separator,
2311 for (i = 0; i < G_N_ELEMENTS (events); i++)
2313 gtk_tree_store_append (store, &iter, NULL);
2314 gtk_tree_store_set (store, &iter,
2315 COL_WHAT_TYPE, events[i].type,
2316 COL_WHAT_SUBTYPE, events[i].subtype,
2317 COL_WHAT_TEXT, events[i].text,
2318 COL_WHAT_ICON, events[i].icon,
2322 gtk_tree_model_iter_nth_child (model, &parent, NULL, 3);
2323 for (i = 0; i < G_N_ELEMENTS (call_events); i++)
2325 gtk_tree_store_append (store, &iter, &parent);
2326 gtk_tree_store_set (store, &iter,
2327 COL_WHAT_TYPE, call_events[i].type,
2328 COL_WHAT_SUBTYPE, call_events[i].subtype,
2329 COL_WHAT_TEXT, call_events[i].text,
2330 COL_WHAT_ICON, call_events[i].icon,
2334 gtk_tree_view_expand_all (view);
2336 /* select 'Anything' */
2337 if (gtk_tree_model_get_iter_first (model, &iter))
2338 gtk_tree_selection_select_iter (selection, &iter);
2340 /* set up signals */
2341 g_signal_connect (view, "test-collapse-row",
2342 G_CALLBACK (log_window_what_collapse_row_cb),
2344 g_signal_connect (selection, "changed",
2345 G_CALLBACK (log_window_what_changed_cb),
2348 g_object_unref (store);
2352 start_spinner (void)
2354 gtk_spinner_start (GTK_SPINNER (log_window->spinner));
2355 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2360 show_spinner (gpointer data)
2364 if (log_window == NULL)
2367 g_object_get (log_window->spinner, "active", &active, NULL);
2370 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2377 show_events (TplActionChain *chain,
2380 gtk_spinner_stop (GTK_SPINNER (log_window->spinner));
2381 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2384 _tpl_action_chain_continue (chain);
2388 log_window_got_messages_for_date_cb (GObject *manager,
2389 GAsyncResult *result,
2392 Ctx *ctx = user_data;
2394 GtkTreeModel *model;
2398 GError *error = NULL;
2401 if (log_window == NULL)
2407 if (log_window->count != ctx->count)
2410 if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (manager),
2411 result, &events, &error))
2413 DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting",
2415 g_error_free (error);
2419 for (l = events; l; l = l->next)
2421 TplEvent *event = l->data;
2422 gboolean append = TRUE;
2424 if (TPL_IS_CALL_EVENT (l->data)
2425 && ctx->event_mask & TPL_EVENT_MASK_CALL
2426 && ctx->event_mask != TPL_EVENT_MASK_ANY)
2428 TplCallEvent *call = l->data;
2432 if (ctx->subtype & EVENT_CALL_ALL)
2438 TplCallEndReason reason = tpl_call_event_get_end_reason (call);
2439 TplEntity *sender = tpl_event_get_sender (event);
2440 TplEntity *receiver = tpl_event_get_receiver (event);
2442 if (reason == TPL_CALL_END_REASON_NO_ANSWER)
2444 if (ctx->subtype & EVENT_CALL_MISSED)
2447 else if (ctx->subtype & EVENT_CALL_OUTGOING
2448 && tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
2452 else if (ctx->subtype & EVENT_CALL_INCOMING
2453 && tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
2462 EmpathyMessage *msg = empathy_message_from_tpl_log_event (event);
2463 log_window_append_message (event, msg);
2464 g_object_unref (msg);
2467 g_object_unref (event);
2469 g_list_free (events);
2471 view = GTK_TREE_VIEW (log_window->treeview_events);
2472 model = gtk_tree_view_get_model (view);
2473 n = gtk_tree_model_iter_n_children (model, NULL) - 1;
2475 if (n >= 0 && gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
2479 path = gtk_tree_model_get_path (model, &iter);
2480 gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0, 0);
2481 gtk_tree_path_free (path);
2487 _tpl_action_chain_continue (log_window->chain);
2491 get_events_for_date (TplActionChain *chain, gpointer user_data)
2493 Ctx *ctx = user_data;
2495 tpl_log_manager_get_events_for_date_async (ctx->window->log_manager,
2496 ctx->account, ctx->entity, ctx->event_mask,
2498 log_window_got_messages_for_date_cb,
2503 log_window_get_messages_for_dates (EmpathyLogWindow *window,
2506 GList *accounts, *targets, *acc, *targ, *l;
2507 TplEventTypeMask event_mask;
2508 EventSubtype subtype;
2509 GDate *date, *anytime, *separator;
2511 if (!log_window_get_selected (window,
2512 &accounts, &targets, NULL, &event_mask, &subtype))
2515 anytime = g_date_new_dmy (2, 1, -1);
2516 separator = g_date_new_dmy (1, 1, -1);
2518 _tpl_action_chain_clear (window->chain);
2521 for (acc = accounts, targ = targets;
2522 acc != NULL && targ != NULL;
2523 acc = acc->next, targ = targ->next)
2525 TpAccount *account = acc->data;
2526 TplEntity *target = targ->data;
2528 for (l = dates; l != NULL; l = l->next)
2533 if (g_date_compare (date, anytime) != 0)
2537 ctx = ctx_new (window, account, target, date, event_mask, subtype,
2539 _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
2543 GtkTreeView *view = GTK_TREE_VIEW (window->treeview_when);
2544 GtkTreeModel *model = gtk_tree_view_get_model (view);
2549 for (next = gtk_tree_model_get_iter_first (model, &iter);
2551 next = gtk_tree_model_iter_next (model, &iter))
2555 gtk_tree_model_get (model, &iter,
2559 if (g_date_compare (d, anytime) != 0 &&
2560 g_date_compare (d, separator) != 0)
2562 ctx = ctx_new (window, account, target, d,
2563 event_mask, subtype, window->count);
2564 _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
2572 g_timeout_add (1000, show_spinner, NULL);
2573 _tpl_action_chain_append (window->chain, show_events, NULL);
2574 _tpl_action_chain_start (window->chain);
2576 g_list_free_full (accounts, g_object_unref);
2577 g_list_free_full (targets, g_object_unref);
2578 g_date_free (separator);
2579 g_date_free (anytime);
2583 log_manager_got_dates_cb (GObject *manager,
2584 GAsyncResult *result,
2587 Ctx *ctx = user_data;
2589 GtkTreeModel *model;
2590 GtkTreeSelection *selection;
2591 GtkListStore *store;
2595 GError *error = NULL;
2597 if (log_window == NULL)
2600 if (log_window->count != ctx->count)
2603 if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager),
2604 result, &dates, &error))
2606 DEBUG ("Unable to retrieve messages' dates: %s. Aborting",
2611 view = GTK_TREE_VIEW (log_window->treeview_when);
2612 model = gtk_tree_view_get_model (view);
2613 store = GTK_LIST_STORE (model);
2614 selection = gtk_tree_view_get_selection (view);
2616 for (l = dates; l != NULL; l = l->next)
2618 GDate *date = l->data;
2620 /* Add the date if it's not already there */
2621 has_element = FALSE;
2622 gtk_tree_model_foreach (model, model_has_date, date);
2625 gchar *text = format_date_for_display (date);
2627 gtk_list_store_append (store, &iter);
2628 gtk_list_store_set (store, &iter,
2629 COL_WHEN_DATE, date,
2630 COL_WHEN_TEXT, text,
2631 COL_WHEN_ICON, CALENDAR_ICON,
2638 if (gtk_tree_model_get_iter_first (model, &iter))
2640 gchar *separator = NULL;
2642 if (gtk_tree_model_iter_next (model, &iter))
2644 gtk_tree_model_get (model, &iter,
2645 COL_WHEN_TEXT, &separator,
2649 if (g_strcmp0 (separator, "separator") != 0)
2651 gtk_list_store_prepend (store, &iter);
2652 gtk_list_store_set (store, &iter,
2653 COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
2654 COL_WHEN_TEXT, "separator",
2657 gtk_list_store_prepend (store, &iter);
2658 gtk_list_store_set (store, &iter,
2659 COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
2660 COL_WHEN_TEXT, _("Anytime"),
2665 g_list_free_full (dates, g_free);
2668 _tpl_action_chain_continue (log_window->chain);
2672 select_first_date (TplActionChain *chain, gpointer user_data)
2675 GtkTreeModel *model;
2676 GtkTreeSelection *selection;
2679 view = GTK_TREE_VIEW (log_window->treeview_when);
2680 model = gtk_tree_view_get_model (view);
2681 selection = gtk_tree_view_get_selection (view);
2683 /* Show messages of the most recent date */
2684 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 2))
2685 gtk_tree_selection_select_iter (selection, &iter);
2687 _tpl_action_chain_continue (log_window->chain);
2691 get_dates_for_entity (TplActionChain *chain, gpointer user_data)
2693 Ctx *ctx = user_data;
2695 tpl_log_manager_get_dates_async (ctx->window->log_manager,
2696 ctx->account, ctx->entity, ctx->event_mask,
2697 log_manager_got_dates_cb, ctx);
2701 log_window_chats_get_messages (EmpathyLogWindow *window,
2702 gboolean force_get_dates)
2704 GList *accounts, *targets, *dates;
2705 TplEventTypeMask event_mask;
2707 GtkTreeModel *model;
2708 GtkListStore *store;
2709 GtkTreeSelection *selection;
2711 if (!log_window_get_selected (window, &accounts, &targets,
2712 &dates, &event_mask, NULL))
2715 view = GTK_TREE_VIEW (window->treeview_when);
2716 selection = gtk_tree_view_get_selection (view);
2717 model = gtk_tree_view_get_model (view);
2718 store = GTK_LIST_STORE (model);
2720 /* Clear all current messages shown in the textview */
2721 gtk_tree_store_clear (window->store_events);
2723 _tpl_action_chain_clear (window->chain);
2726 /* If there's a search use the returned hits */
2727 if (window->hits != NULL)
2729 if (force_get_dates)
2731 g_signal_handlers_block_by_func (selection,
2732 log_window_when_changed_cb,
2735 gtk_list_store_clear (store);
2737 g_signal_handlers_unblock_by_func (selection,
2738 log_window_when_changed_cb,
2741 populate_dates_from_search_hits (accounts, targets);
2745 populate_events_from_search_hits (accounts, targets, dates);
2748 /* Either use the supplied date or get the last */
2749 else if (force_get_dates || dates == NULL)
2753 g_signal_handlers_block_by_func (selection,
2754 log_window_when_changed_cb,
2757 gtk_list_store_clear (store);
2759 g_signal_handlers_unblock_by_func (selection,
2760 log_window_when_changed_cb,
2763 /* Get a list of dates and show them on the treeview */
2764 for (targ = targets, acc = accounts;
2765 targ != NULL && acc != NULL;
2766 targ = targ->next, acc = acc->next)
2768 TpAccount *account = acc->data;
2769 TplEntity *target = targ->data;
2770 Ctx *ctx = ctx_new (window, account, target, NULL, event_mask, 0,
2773 _tpl_action_chain_append (window->chain, get_dates_for_entity, ctx);
2775 _tpl_action_chain_append (window->chain, select_first_date, NULL);
2776 _tpl_action_chain_start (window->chain);
2780 /* Show messages of the selected date */
2781 log_window_get_messages_for_dates (window, dates);
2784 g_list_free_full (accounts, g_object_unref);
2785 g_list_free_full (targets, g_object_unref);
2786 g_list_free_full (dates, (GFreeFunc) g_date_free);
2790 EmpathyAccountChooserFilterResultCallback callback;
2792 } FilterCallbackData;
2795 got_entities (GObject *manager,
2796 GAsyncResult *result,
2799 FilterCallbackData *data = user_data;
2801 GError *error = NULL;
2803 if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
2804 result, &entities, &error))
2806 DEBUG ("Could not get entities: %s", error->message);
2807 g_error_free (error);
2808 data->callback (FALSE, data->user_data);
2812 data->callback (entities != NULL, data->user_data);
2814 g_list_free_full (entities, g_object_unref);
2817 g_slice_free (FilterCallbackData, data);
2821 empathy_account_chooser_filter_has_logs (TpAccount *account,
2822 EmpathyAccountChooserFilterResultCallback callback,
2823 gpointer callback_data,
2826 TplLogManager *manager = tpl_log_manager_dup_singleton ();
2827 FilterCallbackData *cb_data = g_slice_new0 (FilterCallbackData);
2829 cb_data->callback = callback;
2830 cb_data->user_data = callback_data;
2832 tpl_log_manager_get_entities_async (manager, account, got_entities, cb_data);
2834 g_object_unref (manager);
2838 log_window_logger_clear_account_cb (TpProxy *proxy,
2839 const GError *error,
2841 GObject *weak_object)
2843 EmpathyLogWindow *window = user_data;
2846 g_warning ("Error when clearing logs: %s", error->message);
2848 /* Refresh the log viewer so the logs are cleared if the account
2849 * has been deleted */
2850 gtk_tree_store_clear (window->store_events);
2851 log_window_who_populate (window);
2853 /* Re-filter the account chooser so the accounts without logs get greyed out */
2854 empathy_account_chooser_set_filter (
2855 EMPATHY_ACCOUNT_CHOOSER (window->account_chooser),
2856 empathy_account_chooser_filter_has_logs, NULL);
2860 log_window_clear_logs_chooser_select_account (EmpathyAccountChooser *chooser,
2861 EmpathyLogWindow *window)
2863 EmpathyAccountChooser *account_chooser;
2865 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
2867 empathy_account_chooser_set_account (chooser,
2868 empathy_account_chooser_get_account (account_chooser));
2872 log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
2873 EmpathyLogWindow *window)
2875 GtkWidget *dialog, *content_area, *hbox, *label;
2876 EmpathyAccountChooser *account_chooser;
2880 GError *error = NULL;
2882 account_chooser = (EmpathyAccountChooser *) empathy_account_chooser_new ();
2883 empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
2884 empathy_account_chooser_set_filter (account_chooser,
2885 empathy_account_chooser_filter_has_logs, NULL);
2887 /* Select the same account as in the history window */
2888 if (empathy_account_chooser_is_ready (account_chooser))
2889 log_window_clear_logs_chooser_select_account (account_chooser, window);
2891 g_signal_connect (account_chooser, "ready",
2892 G_CALLBACK (log_window_clear_logs_chooser_select_account), window);
2894 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window->window),
2895 GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
2897 _("Are you sure you want to delete all logs of previous conversations?"));
2899 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2900 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2901 _("Clear All"), GTK_RESPONSE_APPLY,
2904 content_area = gtk_message_dialog_get_message_area (
2905 GTK_MESSAGE_DIALOG (dialog));
2907 hbox = gtk_hbox_new (FALSE, 6);
2908 label = gtk_label_new (_("Delete from:"));
2909 gtk_box_pack_start (GTK_BOX (hbox), label,
2911 gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (account_chooser),
2913 gtk_box_pack_start (GTK_BOX (content_area), hbox,
2916 gtk_widget_show_all (hbox);
2918 response_id = gtk_dialog_run (GTK_DIALOG (dialog));
2920 if (response_id != GTK_RESPONSE_APPLY)
2923 bus = tp_dbus_daemon_dup (&error);
2926 g_warning ("Could not delete logs: %s", error->message);
2927 g_error_free (error);
2931 logger = g_object_new (TP_TYPE_PROXY,
2932 "bus-name", "org.freedesktop.Telepathy.Logger",
2933 "object-path", "/org/freedesktop/Telepathy/Logger",
2936 g_object_unref (bus);
2938 tp_proxy_add_interface_by_id (logger, EMP_IFACE_QUARK_LOGGER);
2940 if (empathy_account_chooser_has_all_selected (account_chooser))
2942 DEBUG ("Deleting logs for all the accounts");
2944 emp_cli_logger_call_clear (logger, -1,
2945 log_window_logger_clear_account_cb,
2946 window, NULL, G_OBJECT (window->window));
2952 account = empathy_account_chooser_get_account (account_chooser);
2954 DEBUG ("Deleting logs for %s", tp_proxy_get_object_path (account));
2956 emp_cli_logger_call_clear_account (logger, -1,
2957 tp_proxy_get_object_path (account),
2958 log_window_logger_clear_account_cb,
2959 window, NULL, G_OBJECT (window->window));
2962 g_object_unref (logger);
2964 gtk_widget_destroy (dialog);