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,
179 COL_EVENTS_PRETTY_DATE,
188 #define CALENDAR_ICON "stock_calendar"
190 /* Seconds between two messages to be considered one conversation */
191 #define MAX_GAP 30*60
193 #define WHAT_TYPE_SEPARATOR -1
197 EVENT_CALL_INCOMING = 1 << 0,
198 EVENT_CALL_OUTGOING = 1 << 1,
199 EVENT_CALL_MISSED = 1 << 2,
200 EVENT_CALL_ALL = 1 << 3,
203 static EmpathyLogWindow *log_window = NULL;
205 static gboolean has_element;
208 #define _date_copy(d) g_date_new_julian (g_date_get_julian (d))
213 EmpathyLogWindow *window;
217 TplEventTypeMask event_mask;
218 EventSubtype subtype;
223 ctx_new (EmpathyLogWindow *window,
227 TplEventTypeMask event_mask,
228 EventSubtype subtype,
231 Ctx *ctx = g_slice_new0 (Ctx);
233 ctx->window = window;
235 ctx->account = g_object_ref (account);
237 ctx->entity = g_object_ref (entity);
239 ctx->date = _date_copy (date);
240 ctx->event_mask = event_mask;
241 ctx->subtype = subtype;
250 tp_clear_object (&ctx->account);
251 tp_clear_object (&ctx->entity);
252 tp_clear_pointer (&ctx->date, g_date_free);
254 g_slice_free (Ctx, ctx);
258 account_chooser_ready_cb (EmpathyAccountChooser *chooser,
259 EmpathyLogWindow *window)
261 /* We'll display the account once the model has been populate with the chats
262 * of this account. */
263 empathy_account_chooser_set_account (EMPATHY_ACCOUNT_CHOOSER (
264 window->account_chooser), window->selected_account);
268 select_account_once_ready (EmpathyLogWindow *self,
270 const gchar *chat_id,
271 gboolean is_chatroom)
273 EmpathyAccountChooser *account_chooser;
275 account_chooser = EMPATHY_ACCOUNT_CHOOSER (self->account_chooser);
277 tp_clear_object (&self->selected_account);
278 self->selected_account = g_object_ref (account);
280 g_free (self->selected_chat_id);
281 self->selected_chat_id = g_strdup (chat_id);
283 self->selected_is_chatroom = is_chatroom;
285 if (empathy_account_chooser_is_ready (account_chooser))
286 account_chooser_ready_cb (account_chooser, self);
288 /* Chat will be selected once the account chooser is ready */
289 g_signal_connect (account_chooser, "ready",
290 G_CALLBACK (account_chooser_ready_cb), self);
294 toolbutton_profile_clicked (GtkToolButton *toolbutton,
295 EmpathyLogWindow *window)
298 GtkTreeSelection *selection;
305 EmpathyContact *contact;
308 g_return_if_fail (window != NULL);
310 view = GTK_TREE_VIEW (log_window->treeview_who);
311 selection = gtk_tree_view_get_selection (view);
313 paths = gtk_tree_selection_get_selected_rows (selection, &model);
314 g_return_if_fail (paths != NULL);
317 gtk_tree_model_get_iter (model, &iter, path);
318 gtk_tree_model_get (model, &iter,
319 COL_WHO_ACCOUNT, &account,
320 COL_WHO_TARGET, &target,
324 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
326 g_return_if_fail (type == COL_TYPE_NORMAL);
328 contact = empathy_contact_from_tpl_contact (account, target);
329 empathy_contact_information_dialog_show (contact,
330 GTK_WINDOW (window->window));
331 g_object_unref (contact);
333 g_object_unref (account);
334 g_object_unref (target);
338 toolbutton_chat_clicked (GtkToolButton *toolbutton,
339 EmpathyLogWindow *window)
342 GtkTreeSelection *selection;
349 EmpathyContact *contact;
352 g_return_if_fail (window != NULL);
354 view = GTK_TREE_VIEW (log_window->treeview_who);
355 selection = gtk_tree_view_get_selection (view);
357 paths = gtk_tree_selection_get_selected_rows (selection, &model);
358 g_return_if_fail (paths != NULL);
361 gtk_tree_model_get_iter (model, &iter, path);
362 gtk_tree_model_get (model, &iter,
363 COL_WHO_ACCOUNT, &account,
364 COL_WHO_TARGET, &target,
368 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
370 g_return_if_fail (type == COL_TYPE_NORMAL);
372 contact = empathy_contact_from_tpl_contact (account, target);
373 empathy_chat_with_contact (contact,
374 gtk_get_current_event_time ());
376 g_object_unref (contact);
377 g_object_unref (account);
378 g_object_unref (target);
382 toolbutton_av_clicked (GtkToolButton *toolbutton,
383 EmpathyLogWindow *window)
386 GtkTreeSelection *selection;
396 g_return_if_fail (window != NULL);
398 view = GTK_TREE_VIEW (log_window->treeview_who);
399 selection = gtk_tree_view_get_selection (view);
401 paths = gtk_tree_selection_get_selected_rows (selection, &model);
402 g_return_if_fail (paths != NULL);
405 gtk_tree_model_get_iter (model, &iter, path);
406 gtk_tree_model_get (model, &iter,
407 COL_WHO_ACCOUNT, &account,
408 COL_WHO_NAME, &contact,
412 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
414 g_return_if_fail (type == COL_TYPE_NORMAL);
416 video = (GTK_WIDGET (toolbutton) == window->button_video);
418 empathy_call_new_with_streams (contact, account,
419 TRUE, video, gtk_get_current_event_time ());
422 g_object_unref (account);
426 empathy_log_window_show (TpAccount *account,
427 const gchar *chat_id,
428 gboolean is_chatroom,
431 EmpathyAccountChooser *account_chooser;
434 EmpathyLogWindow *window;
435 GtkWidget *vbox, *accounts, *search, *label, *quit;
437 if (log_window != NULL)
439 gtk_window_present (GTK_WINDOW (log_window->window));
441 if (account != NULL && chat_id != NULL)
442 select_account_once_ready (log_window, account, chat_id, is_chatroom);
444 return log_window->window;
447 log_window = g_new0 (EmpathyLogWindow, 1);
448 log_window->chain = _tpl_action_chain_new_async (NULL, NULL, NULL);
450 log_window->log_manager = tpl_log_manager_dup_singleton ();
454 filename = empathy_file_lookup ("empathy-log-window.ui", "libempathy-gtk");
455 gui = empathy_builder_get_file (filename,
456 "log_window", &window->window,
457 "toolbutton_profile", &window->button_profile,
458 "toolbutton_chat", &window->button_chat,
459 "toolbutton_call", &window->button_call,
460 "toolbutton_video", &window->button_video,
461 "toolbutton_accounts", &accounts,
462 "toolbutton_search", &search,
463 "imagemenuitem_quit", &quit,
464 "treeview_who", &window->treeview_who,
465 "treeview_what", &window->treeview_what,
466 "treeview_when", &window->treeview_when,
467 "treeview_events", &window->treeview_events,
468 "notebook", &window->notebook,
469 "spinner", &window->spinner,
473 empathy_builder_connect (gui, window,
474 "log_window", "destroy", log_window_destroy_cb,
475 "toolbutton_profile", "clicked", toolbutton_profile_clicked,
476 "toolbutton_chat", "clicked", toolbutton_chat_clicked,
477 "toolbutton_call", "clicked", toolbutton_av_clicked,
478 "toolbutton_video", "clicked", toolbutton_av_clicked,
479 "imagemenuitem_delete", "activate", log_window_delete_menu_clicked_cb,
482 g_object_unref (gui);
484 g_object_add_weak_pointer (G_OBJECT (window->window),
485 (gpointer) &log_window);
487 g_signal_connect_swapped (quit, "activate",
488 G_CALLBACK (gtk_widget_destroy), window->window);
490 /* Account chooser for chats */
491 vbox = gtk_vbox_new (FALSE, 3);
493 window->account_chooser = empathy_account_chooser_new ();
494 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
495 empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
496 empathy_account_chooser_set_filter (account_chooser,
497 empathy_account_chooser_filter_has_logs, NULL);
498 empathy_account_chooser_set_all (account_chooser);
500 g_signal_connect (window->account_chooser, "changed",
501 G_CALLBACK (log_window_chats_accounts_changed_cb),
504 label = gtk_label_new (_("Show"));
506 gtk_box_pack_start (GTK_BOX (vbox),
507 window->account_chooser,
510 gtk_box_pack_start (GTK_BOX (vbox),
514 gtk_widget_show_all (vbox);
515 gtk_container_add (GTK_CONTAINER (accounts), vbox);
518 vbox = gtk_vbox_new (FALSE, 3);
520 window->search_entry = gtk_entry_new ();
521 gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
522 GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_FIND);
523 gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry),
524 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
526 label = gtk_label_new (_("Search"));
528 gtk_box_pack_start (GTK_BOX (vbox),
529 window->search_entry,
532 gtk_box_pack_start (GTK_BOX (vbox),
536 gtk_widget_show_all (vbox);
537 gtk_container_add (GTK_CONTAINER (search), vbox);
539 g_signal_connect (window->search_entry, "changed",
540 G_CALLBACK (log_window_search_entry_changed_cb),
543 g_signal_connect (window->search_entry, "activate",
544 G_CALLBACK (log_window_search_entry_activate_cb),
547 g_signal_connect (window->search_entry, "icon-press",
548 G_CALLBACK (log_window_search_entry_icon_pressed_cb),
552 log_window_events_setup (window);
553 log_window_who_setup (window);
554 log_window_what_setup (window);
555 log_window_when_setup (window);
557 log_window_who_populate (window);
559 if (account != NULL && chat_id != NULL)
560 select_account_once_ready (window, account, chat_id, is_chatroom);
563 gtk_window_set_transient_for (GTK_WINDOW (window->window),
564 GTK_WINDOW (parent));
566 gtk_widget_show (window->window);
568 return window->window;
572 log_window_destroy_cb (GtkWidget *widget,
573 EmpathyLogWindow *window)
575 if (window->source != 0)
576 g_source_remove (window->source);
578 g_free (window->last_find);
579 _tpl_action_chain_free (window->chain);
580 g_object_unref (window->log_manager);
581 tp_clear_object (&window->selected_account);
582 g_free (window->selected_chat_id);
588 account_equal (TpAccount *a,
591 return g_str_equal (tp_proxy_get_object_path (a),
592 tp_proxy_get_object_path (b));
596 entity_equal (TplEntity *a,
599 return g_str_equal (tpl_entity_get_identifier (a),
600 tpl_entity_get_identifier (b));
604 is_same_confroom (TplEvent *e1,
607 TplEntity *sender1 = tpl_event_get_sender (e1);
608 TplEntity *receiver1 = tpl_event_get_receiver (e1);
609 TplEntity *sender2 = tpl_event_get_sender (e2);
610 TplEntity *receiver2 = tpl_event_get_receiver (e2);
611 TplEntity *room1, *room2;
613 if (tpl_entity_get_entity_type (sender1) == TPL_ENTITY_ROOM)
615 else if (tpl_entity_get_entity_type (receiver1) == TPL_ENTITY_ROOM)
620 if (tpl_entity_get_entity_type (sender2) == TPL_ENTITY_ROOM)
622 else if (tpl_entity_get_entity_type (receiver2) == TPL_ENTITY_ROOM)
627 return g_str_equal (tpl_entity_get_identifier (room1),
628 tpl_entity_get_identifier (room1));
632 event_get_target (TplEvent *event)
634 TplEntity *sender = tpl_event_get_sender (event);
635 TplEntity *receiver = tpl_event_get_receiver (event);
637 if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
644 model_is_parent (GtkTreeModel *model,
648 TplEvent *stored_event;
651 gboolean found = FALSE;
654 if (gtk_tree_model_iter_parent (model, &parent, iter))
657 gtk_tree_model_get (model, iter,
658 COL_EVENTS_ACCOUNT, &account,
659 COL_EVENTS_TARGET, &target,
660 COL_EVENTS_EVENT, &stored_event,
663 if (G_OBJECT_TYPE (event) == G_OBJECT_TYPE (stored_event) &&
664 account_equal (account, tpl_event_get_account (event)) &&
665 (entity_equal (target, event_get_target (event)) ||
666 is_same_confroom (event, stored_event)))
671 gtk_tree_model_iter_nth_child (model, &child, iter,
672 gtk_tree_model_iter_n_children (model, iter) - 1);
674 gtk_tree_model_get (model, &child,
675 COL_EVENTS_TS, ×tamp,
678 if (ABS (tpl_event_get_timestamp (event) - timestamp) < MAX_GAP)
680 /* The gap is smaller than 30 min */
685 g_object_unref (stored_event);
686 g_object_unref (account);
687 g_object_unref (target);
693 get_contact_alias_for_message (EmpathyMessage *message)
695 EmpathyContact *sender, *receiver;
697 sender = empathy_message_get_sender (message);
698 receiver = empathy_message_get_receiver (message);
700 if (empathy_contact_is_user (sender))
701 return empathy_contact_get_alias (receiver);
703 return empathy_contact_get_alias (sender);
707 get_parent_iter_for_message (TplEvent *event,
708 EmpathyMessage *message,
714 gboolean parent_found = FALSE;
717 store = log_window->store_events;
718 model = GTK_TREE_MODEL (store);
720 for (next = gtk_tree_model_get_iter_first (model, &iter);
722 next = gtk_tree_model_iter_next (model, &iter))
724 if ((parent_found = model_is_parent (model, &iter, event)))
735 gchar *body, *pretty_date;
737 date = g_date_time_new_from_unix_utc (
738 tpl_event_get_timestamp (event));
740 pretty_date = g_date_time_format (date,
741 C_("A date with the time", "%A, %e %B %Y %X"));
743 body = g_strdup_printf (_("Chat with %s"),
744 get_contact_alias_for_message (message));
746 gtk_tree_store_append (store, &iter, NULL);
747 gtk_tree_store_set (store, &iter,
748 COL_EVENTS_TS, tpl_event_get_timestamp (event),
749 COL_EVENTS_PRETTY_DATE, pretty_date,
750 COL_EVENTS_TEXT, body,
751 COL_EVENTS_ICON, "stock_text_justify",
752 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
753 COL_EVENTS_TARGET, event_get_target (event),
754 COL_EVENTS_EVENT, event,
760 g_free (pretty_date);
761 g_date_time_unref (date);
766 get_icon_for_event (TplEvent *event)
768 const gchar *icon = NULL;
770 if (TPL_IS_CALL_EVENT (event))
772 TplCallEvent *call = TPL_CALL_EVENT (event);
773 TplCallEndReason reason = tpl_call_event_get_end_reason (call);
774 TplEntity *sender = tpl_event_get_sender (event);
775 TplEntity *receiver = tpl_event_get_receiver (event);
777 if (reason == TPL_CALL_END_REASON_NO_ANSWER)
778 icon = EMPATHY_IMAGE_CALL_MISSED;
779 else if (tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
780 icon = EMPATHY_IMAGE_CALL_OUTGOING;
781 else if (tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
782 icon = EMPATHY_IMAGE_CALL_INCOMING;
789 log_window_append_chat_message (TplEvent *event,
790 EmpathyMessage *message)
792 GtkTreeStore *store = log_window->store_events;
793 GtkTreeIter iter, parent;
794 gchar *pretty_date, *body;
797 date = g_date_time_new_from_unix_utc (
798 tpl_event_get_timestamp (event));
800 pretty_date = g_date_time_format (date, "%X");
802 get_parent_iter_for_message (event, message, &parent);
804 if (tpl_text_event_get_message_type (TPL_TEXT_EVENT (event))
805 == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION)
807 body = g_strdup_printf ("* %s %s",
808 tpl_entity_get_alias (tpl_event_get_sender (event)),
809 empathy_message_get_body (message));
813 body = g_strdup_printf (
814 C_("First is a contact, second is what was said", "%s: %s"),
815 tpl_entity_get_alias (tpl_event_get_sender (event)),
816 empathy_message_get_body (message));
819 gtk_tree_store_append (store, &iter, &parent);
820 gtk_tree_store_set (store, &iter,
821 COL_EVENTS_TS, tpl_event_get_timestamp (event),
822 COL_EVENTS_PRETTY_DATE, pretty_date,
823 COL_EVENTS_TEXT, body,
824 COL_EVENTS_ICON, get_icon_for_event (event),
825 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
826 COL_EVENTS_TARGET, event_get_target (event),
827 COL_EVENTS_EVENT, event,
831 g_free (pretty_date);
832 g_date_time_unref (date);
836 log_window_append_call (TplEvent *event,
837 EmpathyMessage *message)
839 TplCallEvent *call = TPL_CALL_EVENT (event);
840 GtkTreeStore *store = log_window->store_events;
841 GtkTreeIter iter, child;
842 gchar *pretty_date, *duration, *finished;
843 GDateTime *started_date, *finished_date;
846 started_date = g_date_time_new_from_unix_utc (
847 tpl_event_get_timestamp (event));
849 pretty_date = g_date_time_format (started_date,
850 C_("A date with the time", "%A, %e %B %Y %X"));
852 gtk_tree_store_append (store, &iter, NULL);
853 gtk_tree_store_set (store, &iter,
854 COL_EVENTS_TS, tpl_event_get_timestamp (event),
855 COL_EVENTS_PRETTY_DATE, pretty_date,
856 COL_EVENTS_TEXT, empathy_message_get_body (message),
857 COL_EVENTS_ICON, get_icon_for_event (event),
858 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
859 COL_EVENTS_TARGET, event_get_target (event),
860 COL_EVENTS_EVENT, event,
863 if (tpl_call_event_get_end_reason (call) != TPL_CALL_END_REASON_NO_ANSWER)
867 span = tpl_call_event_get_duration (TPL_CALL_EVENT (event));
869 duration = g_strdup_printf (_("%" G_GINT64_FORMAT " seconds"), span);
871 duration = g_strdup_printf (_("%" G_GINT64_FORMAT " minutes"),
874 finished_date = g_date_time_add (started_date, -span);
875 finished = g_date_time_format (finished_date, "%X");
876 g_date_time_unref (finished_date);
878 body = g_strdup_printf (_("Call took %s, ended at %s"),
884 gtk_tree_store_append (store, &child, &iter);
885 gtk_tree_store_set (store, &child,
886 COL_EVENTS_TS, tpl_event_get_timestamp (event),
887 COL_EVENTS_TEXT, body,
888 COL_EVENTS_ACCOUNT, tpl_event_get_account (event),
889 COL_EVENTS_TARGET, event_get_target (event),
890 COL_EVENTS_EVENT, event,
896 g_free (pretty_date);
897 g_date_time_unref (started_date);
901 log_window_append_message (TplEvent *event,
902 EmpathyMessage *message)
904 if (TPL_IS_TEXT_EVENT (event))
905 log_window_append_chat_message (event, message);
906 else if (TPL_IS_CALL_EVENT (event))
907 log_window_append_call (event, message);
909 DEBUG ("Message type not handled");
913 add_all_accounts_and_entities (GList **accounts,
920 view = GTK_TREE_VIEW (log_window->treeview_who);
921 model = gtk_tree_view_get_model (view);
923 if (!gtk_tree_model_get_iter_first (model, &iter))
932 gtk_tree_model_get (model, &iter,
933 COL_WHO_ACCOUNT, &account,
934 COL_WHO_TARGET, &entity,
938 if (type != COL_TYPE_NORMAL)
941 if (accounts != NULL)
942 *accounts = g_list_append (*accounts, account);
944 if (entities != NULL)
945 *entities = g_list_append (*entities, entity);
947 while (gtk_tree_model_iter_next (model, &iter));
951 log_window_get_selected (EmpathyLogWindow *window,
955 TplEventTypeMask *event_mask,
956 EventSubtype *subtype)
960 GtkTreeSelection *selection;
962 TplEventTypeMask ev = 0;
967 view = GTK_TREE_VIEW (window->treeview_who);
968 model = gtk_tree_view_get_model (view);
969 selection = gtk_tree_view_get_selection (view);
971 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
975 if (accounts != NULL)
977 if (entities != NULL)
980 for (l = paths; l != NULL; l = l->next)
982 GtkTreePath *path = l->data;
986 gtk_tree_model_get_iter (model, &iter, path);
987 gtk_tree_model_get (model, &iter,
988 COL_WHO_ACCOUNT, &account,
989 COL_WHO_TARGET, &entity,
993 if (type == COL_TYPE_ANY)
995 if (accounts != NULL || entities != NULL)
996 add_all_accounts_and_entities (accounts, entities);
1000 if (accounts != NULL)
1001 *accounts = g_list_append (*accounts, g_object_ref (account));
1003 if (entities != NULL)
1004 *entities = g_list_append (*entities, g_object_ref (entity));
1006 g_object_unref (account);
1007 g_object_unref (entity);
1009 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1011 view = GTK_TREE_VIEW (window->treeview_what);
1012 model = gtk_tree_view_get_model (view);
1013 selection = gtk_tree_view_get_selection (view);
1015 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1016 for (l = paths; l != NULL; l = l->next)
1018 GtkTreePath *path = l->data;
1019 TplEventTypeMask mask;
1020 EventSubtype submask;
1022 gtk_tree_model_get_iter (model, &iter, path);
1023 gtk_tree_model_get (model, &iter,
1024 COL_WHAT_TYPE, &mask,
1025 COL_WHAT_SUBTYPE, &submask,
1031 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1033 view = GTK_TREE_VIEW (window->treeview_when);
1034 model = gtk_tree_view_get_model (view);
1035 selection = gtk_tree_view_get_selection (view);
1041 paths = gtk_tree_selection_get_selected_rows (selection, NULL);
1042 for (l = paths; l != NULL; l = l->next)
1044 GtkTreePath *path = l->data;
1047 gtk_tree_model_get_iter (model, &iter, path);
1048 gtk_tree_model_get (model, &iter,
1049 COL_WHEN_DATE, &date,
1052 *dates = g_list_append (*dates, date);
1054 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1057 if (event_mask != NULL)
1060 if (subtype != NULL)
1067 model_has_entity (GtkTreeModel *model,
1072 TplLogSearchHit *hit = data;
1075 gboolean ret = FALSE;
1077 gtk_tree_model_get (model, iter,
1079 COL_WHO_ACCOUNT, &a,
1082 if (e != NULL && entity_equal (hit->target, e) &&
1083 a != NULL && account_equal (hit->account, a))
1085 ret = has_element = TRUE;
1088 tp_clear_object (&e);
1089 tp_clear_object (&a);
1095 model_has_date (GtkTreeModel *model,
1103 gtk_tree_model_get (model, iter,
1107 if (!g_date_compare (date, d))
1117 get_events_for_date (TplActionChain *chain, gpointer user_data);
1120 populate_events_from_search_hits (GList *accounts,
1124 TplEventTypeMask event_mask;
1125 EventSubtype subtype;
1128 gboolean is_anytime = FALSE;
1130 if (!log_window_get_selected (log_window,
1131 NULL, NULL, NULL, &event_mask, &subtype))
1134 anytime = g_date_new_dmy (2, 1, -1);
1135 if (g_list_find_custom (dates, anytime, (GCompareFunc) g_date_compare))
1138 for (l = log_window->hits; l != NULL; l = l->next)
1140 TplLogSearchHit *hit = l->data;
1142 gboolean found = FALSE;
1144 /* Protect against invalid data (corrupt or old log files). */
1145 if (hit->account == NULL || hit->target == NULL)
1148 for (acc = accounts, targ = targets;
1149 acc != NULL && targ != NULL && !found;
1150 acc = acc->next, targ = targ->next)
1152 TpAccount *account = acc->data;
1153 TplEntity *target = targ->data;
1155 if (account_equal (hit->account, account) &&
1156 entity_equal (hit->target, target))
1164 g_list_find_custom (dates, hit->date, (GCompareFunc) g_date_compare)
1169 ctx = ctx_new (log_window, hit->account, hit->target, hit->date,
1170 event_mask, subtype, log_window->count);
1171 _tpl_action_chain_append (log_window->chain,
1172 get_events_for_date, ctx);
1176 _tpl_action_chain_start (log_window->chain);
1178 g_date_free (anytime);
1182 format_date_for_display (GDate *date)
1188 /* g_date_strftime sucks */
1190 now = g_date_new ();
1191 g_date_set_time_t (now, time (NULL));
1193 days_elapsed = g_date_days_between (date, now);
1195 if (days_elapsed < 0)
1199 else if (days_elapsed == 0)
1201 text = g_strdup (_("Today"));
1203 else if (days_elapsed == 1)
1205 text = g_strdup (_("Yesterday"));
1211 dt = g_date_time_new_utc (g_date_get_year (date),
1212 g_date_get_month (date), g_date_get_day (date),
1215 if (days_elapsed <= 7)
1216 text = g_date_time_format (dt, "%A");
1218 text = g_date_time_format (dt,
1219 C_("A date such as '23 May 2010', "
1220 "%e is the day, %B the month and %Y the year",
1223 g_date_time_unref (dt);
1232 populate_dates_from_search_hits (GList *accounts,
1237 GtkTreeModel *model;
1238 GtkListStore *store;
1239 GtkTreeSelection *selection;
1242 if (log_window == NULL)
1245 view = GTK_TREE_VIEW (log_window->treeview_when);
1246 model = gtk_tree_view_get_model (view);
1247 store = GTK_LIST_STORE (model);
1248 selection = gtk_tree_view_get_selection (view);
1250 for (l = log_window->hits; l != NULL; l = l->next)
1252 TplLogSearchHit *hit = l->data;
1254 gboolean found = FALSE;
1256 /* Protect against invalid data (corrupt or old log files). */
1257 if (hit->account == NULL || hit->target == NULL)
1260 for (acc = accounts, targ = targets;
1261 acc != NULL && targ != NULL && !found;
1262 acc = acc->next, targ = targ->next)
1264 TpAccount *account = acc->data;
1265 TplEntity *target = targ->data;
1267 if (account_equal (hit->account, account) &&
1268 entity_equal (hit->target, target))
1275 /* Add the date if it's not already there */
1276 has_element = FALSE;
1277 gtk_tree_model_foreach (model, model_has_date, hit->date);
1280 gchar *text = format_date_for_display (hit->date);
1282 gtk_list_store_append (store, &iter);
1283 gtk_list_store_set (store, &iter,
1284 COL_WHEN_DATE, hit->date,
1285 COL_WHEN_TEXT, text,
1286 COL_WHEN_ICON, CALENDAR_ICON,
1291 if (gtk_tree_model_get_iter_first (model, &iter))
1293 gtk_list_store_prepend (store, &iter);
1294 gtk_list_store_set (store, &iter,
1295 COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
1296 COL_WHEN_TEXT, "separator",
1299 gtk_list_store_prepend (store, &iter);
1300 gtk_list_store_set (store, &iter,
1301 COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
1302 COL_WHEN_TEXT, _("Anytime"),
1305 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 2))
1306 gtk_tree_selection_select_iter (selection, &iter);
1311 populate_entities_from_search_hits (void)
1313 EmpathyAccountChooser *account_chooser;
1316 GtkTreeModel *model;
1318 GtkListStore *store;
1321 view = GTK_TREE_VIEW (log_window->treeview_who);
1322 model = gtk_tree_view_get_model (view);
1323 store = GTK_LIST_STORE (model);
1325 gtk_list_store_clear (store);
1327 account_chooser = EMPATHY_ACCOUNT_CHOOSER (log_window->account_chooser);
1328 account = empathy_account_chooser_get_account (account_chooser);
1330 for (l = log_window->hits; l; l = l->next)
1332 TplLogSearchHit *hit = l->data;
1334 /* Protect against invalid data (corrupt or old log files). */
1335 if (hit->account == NULL || hit->target == NULL)
1338 /* Filter based on the selected account */
1339 if (account != NULL && !account_equal (account, hit->account))
1342 /* Add the entity if it's not already there */
1343 has_element = FALSE;
1344 gtk_tree_model_foreach (model, model_has_entity, hit);
1347 TplEntityType type = tpl_entity_get_entity_type (hit->target);
1348 gboolean room = type == TPL_ENTITY_ROOM;
1350 gtk_list_store_append (store, &iter);
1351 gtk_list_store_set (store, &iter,
1352 COL_WHO_TYPE, COL_TYPE_NORMAL,
1353 COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
1354 : EMPATHY_IMAGE_AVATAR_DEFAULT,
1355 COL_WHO_NAME, tpl_entity_get_alias (hit->target),
1356 COL_WHO_ACCOUNT, hit->account,
1357 COL_WHO_TARGET, hit->target,
1362 if (gtk_tree_model_get_iter_first (model, &iter))
1364 gtk_list_store_prepend (store, &iter);
1365 gtk_list_store_set (store, &iter,
1366 COL_WHO_TYPE, COL_TYPE_SEPARATOR,
1367 COL_WHO_NAME, "separator",
1370 gtk_list_store_prepend (store, &iter);
1371 gtk_list_store_set (store, &iter,
1372 COL_WHO_TYPE, COL_TYPE_ANY,
1373 COL_WHO_NAME, _("Anyone"),
1377 /* FIXME: select old entity if still available */
1381 log_manager_searched_new_cb (GObject *manager,
1382 GAsyncResult *result,
1387 GtkTreeSelection *selection;
1388 GError *error = NULL;
1390 if (log_window == NULL)
1393 if (!tpl_log_manager_search_finish (TPL_LOG_MANAGER (manager),
1394 result, &hits, &error))
1396 DEBUG ("%s. Aborting", error->message);
1397 g_error_free (error);
1401 tp_clear_pointer (&log_window->hits, tpl_log_manager_search_free);
1402 log_window->hits = hits;
1404 populate_entities_from_search_hits ();
1406 view = GTK_TREE_VIEW (log_window->treeview_when);
1407 selection = gtk_tree_view_get_selection (view);
1409 g_signal_handlers_unblock_by_func (selection,
1410 log_window_when_changed_cb,
1415 log_window_find_populate (EmpathyLogWindow *window,
1416 const gchar *search_criteria)
1419 GtkTreeModel *model;
1420 GtkTreeSelection *selection;
1421 GtkListStore *store;
1423 gtk_tree_store_clear (window->store_events);
1425 view = GTK_TREE_VIEW (window->treeview_who);
1426 model = gtk_tree_view_get_model (view);
1427 store = GTK_LIST_STORE (model);
1429 gtk_list_store_clear (store);
1431 view = GTK_TREE_VIEW (window->treeview_when);
1432 model = gtk_tree_view_get_model (view);
1433 store = GTK_LIST_STORE (model);
1434 selection = gtk_tree_view_get_selection (view);
1436 gtk_list_store_clear (store);
1438 if (EMP_STR_EMPTY (search_criteria))
1440 tp_clear_pointer (&window->hits, tpl_log_manager_search_free);
1441 log_window_who_populate (window);
1445 g_signal_handlers_block_by_func (selection,
1446 log_window_when_changed_cb,
1449 tpl_log_manager_search_async (window->log_manager,
1450 search_criteria, TPL_EVENT_MASK_ANY,
1451 log_manager_searched_new_cb, NULL);
1455 start_find_search (EmpathyLogWindow *window)
1459 str = gtk_entry_get_text (GTK_ENTRY (window->search_entry));
1461 /* Don't find the same crap again */
1462 if (window->last_find && !tp_strdiff (window->last_find, str))
1465 g_free (window->last_find);
1466 window->last_find = g_strdup (str);
1468 log_window_find_populate (window, str);
1474 log_window_search_entry_changed_cb (GtkWidget *entry,
1475 EmpathyLogWindow *window)
1477 if (window->source != 0)
1478 g_source_remove (window->source);
1479 window->source = g_timeout_add (500, (GSourceFunc) start_find_search,
1484 log_window_search_entry_activate_cb (GtkWidget *entry,
1485 EmpathyLogWindow *self)
1487 start_find_search (self);
1491 log_window_search_entry_icon_pressed_cb (GtkEntry *entry,
1492 GtkEntryIconPosition icon_pos,
1496 if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
1499 gtk_entry_buffer_set_text (gtk_entry_get_buffer (entry),
1504 log_window_update_buttons_sensitivity (EmpathyLogWindow *window,
1505 GtkTreeModel *model,
1506 GtkTreeSelection *selection)
1508 EmpathyContact *contact;
1509 EmpathyCapabilities capabilities;
1515 gboolean profile, chat, call, video;
1517 profile = chat = call = video = FALSE;
1519 if (!gtk_tree_model_get_iter_first (model, &iter))
1522 if (gtk_tree_selection_count_selected_rows (selection) != 1)
1525 if (gtk_tree_selection_iter_is_selected (selection, &iter))
1528 paths = gtk_tree_selection_get_selected_rows (selection, &model);
1529 g_return_if_fail (paths != NULL);
1532 gtk_tree_model_get_iter (model, &iter, path);
1533 gtk_tree_model_get (model, &iter,
1534 COL_WHO_ACCOUNT, &account,
1535 COL_WHO_TARGET, &target,
1538 g_list_free_full (paths, (GDestroyNotify) gtk_tree_path_free);
1540 contact = empathy_contact_from_tpl_contact (account, target);
1542 g_object_unref (account);
1543 g_object_unref (target);
1545 capabilities = empathy_contact_get_capabilities (contact);
1547 profile = chat = TRUE;
1548 call = capabilities & EMPATHY_CAPABILITIES_AUDIO;
1549 video = capabilities & EMPATHY_CAPABILITIES_VIDEO;
1552 gtk_widget_set_sensitive (window->button_profile, profile);
1553 gtk_widget_set_sensitive (window->button_chat, chat);
1554 gtk_widget_set_sensitive (window->button_call, call);
1555 gtk_widget_set_sensitive (window->button_video, video);
1559 log_window_who_changed_cb (GtkTreeSelection *selection,
1560 EmpathyLogWindow *window)
1563 GtkTreeModel *model;
1566 DEBUG ("log_window_who_changed_cb");
1568 view = gtk_tree_selection_get_tree_view (selection);
1569 model = gtk_tree_view_get_model (view);
1571 if (gtk_tree_model_get_iter_first (model, &iter))
1573 /* If 'Anyone' is selected, everything else should be deselected */
1574 if (gtk_tree_selection_iter_is_selected (selection, &iter))
1576 g_signal_handlers_block_by_func (selection,
1577 log_window_who_changed_cb,
1580 gtk_tree_selection_unselect_all (selection);
1581 gtk_tree_selection_select_iter (selection, &iter);
1583 g_signal_handlers_unblock_by_func (selection,
1584 log_window_who_changed_cb,
1589 log_window_update_buttons_sensitivity (window, model, selection);
1591 /* The contact changed, so the dates need to be updated */
1592 log_window_chats_get_messages (window, TRUE);
1596 log_manager_got_entities_cb (GObject *manager,
1597 GAsyncResult *result,
1600 Ctx *ctx = user_data;
1604 GtkTreeModel *model;
1605 GtkTreeSelection *selection;
1606 GtkListStore *store;
1608 GError *error = NULL;
1609 gboolean select_account = FALSE;
1611 if (log_window == NULL)
1614 if (log_window->count != ctx->count)
1617 if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
1618 result, &entities, &error))
1620 DEBUG ("%s. Aborting", error->message);
1621 g_error_free (error);
1625 view = GTK_TREE_VIEW (ctx->window->treeview_who);
1626 model = gtk_tree_view_get_model (view);
1627 selection = gtk_tree_view_get_selection (view);
1628 store = GTK_LIST_STORE (model);
1630 /* Block signals to stop the logs being retrieved prematurely */
1631 g_signal_handlers_block_by_func (selection,
1632 log_window_who_changed_cb, ctx->window);
1634 for (l = entities; l; l = l->next)
1636 TplEntity *entity = TPL_ENTITY (l->data);
1637 TplEntityType type = tpl_entity_get_entity_type (entity);
1638 gboolean room = type == TPL_ENTITY_ROOM;
1640 gtk_list_store_append (store, &iter);
1641 gtk_list_store_set (store, &iter,
1642 COL_WHO_TYPE, COL_TYPE_NORMAL,
1643 COL_WHO_ICON, room ? EMPATHY_IMAGE_GROUP_MESSAGE
1644 : EMPATHY_IMAGE_AVATAR_DEFAULT,
1645 COL_WHO_NAME, tpl_entity_get_alias (entity),
1646 COL_WHO_ACCOUNT, ctx->account,
1647 COL_WHO_TARGET, entity,
1650 if (ctx->window->selected_account != NULL &&
1651 !tp_strdiff (tp_proxy_get_object_path (ctx->account),
1652 tp_proxy_get_object_path (ctx->window->selected_account)))
1653 select_account = TRUE;
1655 g_list_free_full (entities, g_object_unref);
1657 if (gtk_tree_model_get_iter_first (model, &iter))
1661 gtk_tree_model_get (model, &iter,
1662 COL_WHO_TYPE, &type,
1665 if (type != COL_TYPE_ANY)
1667 gtk_list_store_prepend (store, &iter);
1668 gtk_list_store_set (store, &iter,
1669 COL_WHO_TYPE, COL_TYPE_SEPARATOR,
1670 COL_WHO_NAME, "separator",
1673 gtk_list_store_prepend (store, &iter);
1674 gtk_list_store_set (store, &iter,
1675 COL_WHO_TYPE, COL_TYPE_ANY,
1676 COL_WHO_NAME, _("Anyone"),
1681 /* Unblock signals */
1682 g_signal_handlers_unblock_by_func (selection,
1683 log_window_who_changed_cb,
1686 /* We display the selected account if we populate the model with chats from
1689 log_window_chats_set_selected (ctx->window);
1692 _tpl_action_chain_continue (log_window->chain);
1697 get_entities_for_account (TplActionChain *chain, gpointer user_data)
1699 Ctx *ctx = user_data;
1701 tpl_log_manager_get_entities_async (ctx->window->log_manager, ctx->account,
1702 log_manager_got_entities_cb, ctx);
1706 select_first_entity (TplActionChain *chain, gpointer user_data)
1709 GtkTreeModel *model;
1710 GtkTreeSelection *selection;
1713 view = GTK_TREE_VIEW (log_window->treeview_who);
1714 model = gtk_tree_view_get_model (view);
1715 selection = gtk_tree_view_get_selection (view);
1717 if (gtk_tree_model_get_iter_first (model, &iter))
1718 gtk_tree_selection_select_iter (selection, &iter);
1720 _tpl_action_chain_continue (log_window->chain);
1724 log_window_who_populate (EmpathyLogWindow *window)
1726 EmpathyAccountChooser *account_chooser;
1728 gboolean all_accounts;
1730 GtkTreeModel *model;
1731 GtkTreeSelection *selection;
1732 GtkListStore *store;
1735 if (window->hits != NULL)
1737 populate_entities_from_search_hits ();
1741 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
1742 account = empathy_account_chooser_dup_account (account_chooser);
1743 all_accounts = empathy_account_chooser_has_all_selected (account_chooser);
1745 view = GTK_TREE_VIEW (window->treeview_who);
1746 model = gtk_tree_view_get_model (view);
1747 selection = gtk_tree_view_get_selection (view);
1748 store = GTK_LIST_STORE (model);
1750 /* Block signals to stop the logs being retrieved prematurely */
1751 g_signal_handlers_block_by_func (selection,
1752 log_window_who_changed_cb,
1755 gtk_list_store_clear (store);
1757 /* Unblock signals */
1758 g_signal_handlers_unblock_by_func (selection,
1759 log_window_who_changed_cb,
1762 _tpl_action_chain_clear (window->chain);
1765 if (!all_accounts && account == NULL)
1769 else if (!all_accounts)
1771 ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
1772 _tpl_action_chain_append (window->chain, get_entities_for_account, ctx);
1776 TpAccountManager *manager;
1777 GList *accounts, *l;
1779 manager = empathy_account_chooser_get_account_manager (account_chooser);
1780 accounts = tp_account_manager_get_valid_accounts (manager);
1782 for (l = accounts; l != NULL; l = l->next)
1786 ctx = ctx_new (window, account, NULL, NULL, 0, 0, window->count);
1787 _tpl_action_chain_append (window->chain,
1788 get_entities_for_account, ctx);
1791 g_list_free (accounts);
1793 _tpl_action_chain_append (window->chain, select_first_entity, NULL);
1794 _tpl_action_chain_start (window->chain);
1798 sort_by_name (GtkTreeModel *model,
1803 gchar *name1, *name2;
1807 gtk_tree_model_get (model, a,
1808 COL_WHO_TYPE, &type1,
1809 COL_WHO_NAME, &name1,
1812 gtk_tree_model_get (model, b,
1813 COL_WHO_TYPE, &type2,
1814 COL_WHO_NAME, &name2,
1817 if (type1 == COL_TYPE_ANY)
1819 else if (type2 == COL_TYPE_ANY)
1821 else if (type1 == COL_TYPE_SEPARATOR)
1823 else if (type2 == COL_TYPE_SEPARATOR)
1826 ret = g_strcmp0 (name1, name2);
1835 who_row_is_separator (GtkTreeModel *model,
1841 gtk_tree_model_get (model, iter,
1842 COL_WHO_TYPE, &type,
1845 return (type == COL_TYPE_SEPARATOR);
1849 log_window_events_setup (EmpathyLogWindow *window)
1852 GtkTreeModel *model;
1853 GtkTreeSelection *selection;
1854 GtkTreeSortable *sortable;
1855 GtkTreeViewColumn *column;
1856 GtkTreeStore *store;
1857 GtkCellRenderer *cell;
1859 view = GTK_TREE_VIEW (window->treeview_events);
1860 selection = gtk_tree_view_get_selection (view);
1863 window->store_events = store = gtk_tree_store_new (COL_EVENTS_COUNT,
1864 G_TYPE_INT, /* type */
1865 G_TYPE_INT64, /* timestamp */
1866 G_TYPE_STRING, /* stringified date */
1867 G_TYPE_STRING, /* icon */
1868 G_TYPE_STRING, /* name */
1869 TP_TYPE_ACCOUNT, /* account */
1870 TPL_TYPE_ENTITY, /* target */
1871 TPL_TYPE_EVENT); /* event */
1873 model = GTK_TREE_MODEL (store);
1874 sortable = GTK_TREE_SORTABLE (store);
1876 gtk_tree_view_set_model (view, model);
1879 column = gtk_tree_view_column_new ();
1881 cell = gtk_cell_renderer_pixbuf_new ();
1882 gtk_tree_view_column_pack_start (column, cell, FALSE);
1883 gtk_tree_view_column_add_attribute (column, cell,
1884 "icon-name", COL_EVENTS_ICON);
1886 cell = gtk_cell_renderer_text_new ();
1887 gtk_tree_view_column_pack_start (column, cell, TRUE);
1888 gtk_tree_view_column_add_attribute (column, cell,
1889 "text", COL_EVENTS_TEXT);
1891 cell = gtk_cell_renderer_text_new ();
1892 g_object_set (cell, "xalign", 1.0, NULL);
1893 gtk_tree_view_column_pack_end (column, cell, FALSE);
1894 gtk_tree_view_column_add_attribute (column, cell,
1895 "text", COL_EVENTS_PRETTY_DATE);
1897 gtk_tree_view_append_column (view, column);
1899 /* set up treeview properties */
1900 gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
1901 gtk_tree_view_set_headers_visible (view, FALSE);
1903 gtk_tree_sortable_set_sort_column_id (sortable,
1905 GTK_SORT_ASCENDING);
1907 g_object_unref (store);
1911 log_window_who_setup (EmpathyLogWindow *window)
1914 GtkTreeModel *model;
1915 GtkTreeSelection *selection;
1916 GtkTreeSortable *sortable;
1917 GtkTreeViewColumn *column;
1918 GtkListStore *store;
1919 GtkCellRenderer *cell;
1921 view = GTK_TREE_VIEW (window->treeview_who);
1922 selection = gtk_tree_view_get_selection (view);
1925 store = gtk_list_store_new (COL_WHO_COUNT,
1926 G_TYPE_INT, /* type */
1927 G_TYPE_STRING, /* icon */
1928 G_TYPE_STRING, /* name */
1929 TP_TYPE_ACCOUNT, /* account */
1930 TPL_TYPE_ENTITY); /* target */
1932 model = GTK_TREE_MODEL (store);
1933 sortable = GTK_TREE_SORTABLE (store);
1935 gtk_tree_view_set_model (view, model);
1938 column = gtk_tree_view_column_new ();
1939 gtk_tree_view_column_set_title (column, _("Who"));
1941 cell = gtk_cell_renderer_pixbuf_new ();
1942 gtk_tree_view_column_pack_start (column, cell, FALSE);
1943 gtk_tree_view_column_add_attribute (column, cell,
1947 cell = gtk_cell_renderer_text_new ();
1948 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1949 gtk_tree_view_column_pack_start (column, cell, TRUE);
1950 gtk_tree_view_column_add_attribute (column, cell,
1954 gtk_tree_view_append_column (view, column);
1956 /* set up treeview properties */
1957 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1958 gtk_tree_view_set_row_separator_func (view, who_row_is_separator,
1961 gtk_tree_sortable_set_sort_column_id (sortable,
1963 GTK_SORT_ASCENDING);
1964 gtk_tree_sortable_set_sort_func (sortable,
1965 COL_WHO_NAME, sort_by_name,
1968 /* set up signals */
1969 g_signal_connect (selection, "changed",
1970 G_CALLBACK (log_window_who_changed_cb), window);
1972 g_object_unref (store);
1976 log_window_chats_accounts_changed_cb (GtkWidget *combobox,
1977 EmpathyLogWindow *window)
1979 /* Clear all current messages shown in the textview */
1980 gtk_tree_store_clear (window->store_events);
1982 log_window_who_populate (window);
1986 log_window_chats_set_selected (EmpathyLogWindow *window)
1989 GtkTreeModel *model;
1990 GtkTreeSelection *selection;
1995 view = GTK_TREE_VIEW (window->treeview_who);
1996 model = gtk_tree_view_get_model (view);
1997 selection = gtk_tree_view_get_selection (view);
1999 for (next = gtk_tree_model_get_iter_first (model, &iter);
2001 next = gtk_tree_model_iter_next (model, &iter))
2003 TpAccount *this_account;
2004 TplEntity *this_target;
2005 const gchar *this_chat_id;
2006 gboolean this_is_chatroom;
2009 gtk_tree_model_get (model, &iter,
2010 COL_WHO_TYPE, &this_type,
2011 COL_WHO_ACCOUNT, &this_account,
2012 COL_WHO_TARGET, &this_target,
2015 if (this_type != COL_TYPE_NORMAL)
2018 this_chat_id = tpl_entity_get_identifier (this_target);
2019 this_is_chatroom = tpl_entity_get_entity_type (this_target)
2022 if (this_account == window->selected_account &&
2023 !tp_strdiff (this_chat_id, window->selected_chat_id) &&
2024 this_is_chatroom == window->selected_is_chatroom)
2026 gtk_tree_selection_select_iter (selection, &iter);
2027 path = gtk_tree_model_get_path (model, &iter);
2028 gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
2029 gtk_tree_path_free (path);
2030 g_object_unref (this_account);
2031 g_object_unref (this_target);
2035 g_object_unref (this_account);
2036 g_object_unref (this_target);
2039 tp_clear_object (&window->selected_account);
2040 tp_clear_pointer (&window->selected_chat_id, g_free);
2044 sort_by_date (GtkTreeModel *model,
2049 GDate *date1, *date2;
2051 gtk_tree_model_get (model, a,
2052 COL_WHEN_DATE, &date1,
2055 gtk_tree_model_get (model, b,
2056 COL_WHEN_DATE, &date2,
2059 return g_date_compare (date1, date2);
2063 when_row_is_separator (GtkTreeModel *model,
2070 gtk_tree_model_get (model, iter,
2071 COL_WHEN_TEXT, &when,
2074 ret = g_str_equal (when, "separator");
2080 log_window_when_changed_cb (GtkTreeSelection *selection,
2081 EmpathyLogWindow *window)
2084 GtkTreeModel *model;
2087 DEBUG ("log_window_when_changed_cb");
2089 view = gtk_tree_selection_get_tree_view (selection);
2090 model = gtk_tree_view_get_model (view);
2092 /* If 'Anytime' is selected, everything else should be deselected */
2093 if (gtk_tree_model_get_iter_first (model, &iter))
2095 if (gtk_tree_selection_iter_is_selected (selection, &iter))
2097 g_signal_handlers_block_by_func (selection,
2098 log_window_when_changed_cb,
2101 gtk_tree_selection_unselect_all (selection);
2102 gtk_tree_selection_select_iter (selection, &iter);
2104 g_signal_handlers_unblock_by_func (selection,
2105 log_window_when_changed_cb,
2110 log_window_chats_get_messages (window, FALSE);
2114 log_window_when_setup (EmpathyLogWindow *window)
2117 GtkTreeModel *model;
2118 GtkTreeSelection *selection;
2119 GtkTreeSortable *sortable;
2120 GtkTreeViewColumn *column;
2121 GtkListStore *store;
2122 GtkCellRenderer *cell;
2124 view = GTK_TREE_VIEW (window->treeview_when);
2125 selection = gtk_tree_view_get_selection (view);
2128 store = gtk_list_store_new (COL_WHEN_COUNT,
2129 G_TYPE_DATE, /* date */
2130 G_TYPE_STRING, /* stringified date */
2131 G_TYPE_STRING); /* icon */
2133 model = GTK_TREE_MODEL (store);
2134 sortable = GTK_TREE_SORTABLE (store);
2136 gtk_tree_view_set_model (view, model);
2139 column = gtk_tree_view_column_new ();
2140 gtk_tree_view_column_set_title (column, _("When"));
2142 cell = gtk_cell_renderer_pixbuf_new ();
2143 gtk_tree_view_column_pack_start (column, cell, FALSE);
2144 gtk_tree_view_column_add_attribute (column, cell,
2145 "icon-name", COL_WHEN_ICON);
2147 cell = gtk_cell_renderer_text_new ();
2148 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2149 gtk_tree_view_column_pack_start (column, cell, TRUE);
2150 gtk_tree_view_column_add_attribute (column, cell,
2154 gtk_tree_view_append_column (view, column);
2156 /* set up treeview properties */
2157 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2158 gtk_tree_view_set_row_separator_func (view, when_row_is_separator,
2160 gtk_tree_sortable_set_sort_column_id (sortable,
2162 GTK_SORT_DESCENDING);
2163 gtk_tree_sortable_set_sort_func (sortable,
2164 COL_WHEN_DATE, sort_by_date,
2167 /* set up signals */
2168 g_signal_connect (selection, "changed",
2169 G_CALLBACK (log_window_when_changed_cb),
2172 g_object_unref (store);
2176 what_row_is_separator (GtkTreeModel *model,
2182 gtk_tree_model_get (model, iter,
2183 COL_WHAT_TYPE, &type,
2186 return (type == WHAT_TYPE_SEPARATOR);
2190 log_window_what_changed_cb (GtkTreeSelection *selection,
2191 EmpathyLogWindow *window)
2194 GtkTreeModel *model;
2197 DEBUG ("log_window_what_changed_cb");
2199 view = gtk_tree_selection_get_tree_view (selection);
2200 model = gtk_tree_view_get_model (view);
2202 /* If 'Anything' is selected, everything else should be deselected */
2203 if (gtk_tree_model_get_iter_first (model, &iter))
2205 if (gtk_tree_selection_iter_is_selected (selection, &iter))
2207 g_signal_handlers_block_by_func (selection,
2208 log_window_what_changed_cb,
2211 gtk_tree_selection_unselect_all (selection);
2212 gtk_tree_selection_select_iter (selection, &iter);
2214 g_signal_handlers_unblock_by_func (selection,
2215 log_window_what_changed_cb,
2220 /* The dates need to be updated if we're not searching */
2221 log_window_chats_get_messages (window, window->hits == NULL);
2225 log_window_what_collapse_row_cb (GtkTreeView *tree_view,
2230 /* Reject collapsing */
2237 EventSubtype subtype;
2243 log_window_what_setup (EmpathyLogWindow *window)
2246 GtkTreeModel *model;
2247 GtkTreeSelection *selection;
2248 GtkTreeSortable *sortable;
2249 GtkTreeViewColumn *column;
2250 GtkTreeIter iter, parent;
2251 GtkTreeStore *store;
2252 GtkCellRenderer *cell;
2254 struct event events [] = {
2255 { TPL_EVENT_MASK_ANY, 0, NULL, _("Anything") },
2256 { WHAT_TYPE_SEPARATOR, 0, NULL, "separator" },
2257 { TPL_EVENT_MASK_TEXT, 0, "stock_text_justify", _("Text chats") },
2258 { TPL_EVENT_MASK_CALL, EVENT_CALL_ALL, "call-start", _("Calls") }
2260 struct event call_events [] = {
2261 { TPL_EVENT_MASK_CALL, EVENT_CALL_INCOMING, "call-start", _("Incoming calls") },
2262 { TPL_EVENT_MASK_CALL, EVENT_CALL_OUTGOING, "call-start", _("Outgoing calls") },
2263 { TPL_EVENT_MASK_CALL, EVENT_CALL_MISSED, "call-stop", _("Missed calls") }
2266 view = GTK_TREE_VIEW (window->treeview_what);
2267 selection = gtk_tree_view_get_selection (view);
2270 store = gtk_tree_store_new (COL_WHAT_COUNT,
2271 G_TYPE_INT, /* history type */
2272 G_TYPE_INT, /* history subtype */
2273 G_TYPE_STRING, /* stringified history type */
2274 G_TYPE_STRING, /* icon */
2275 G_TYPE_BOOLEAN); /* expander (hidden) */
2277 model = GTK_TREE_MODEL (store);
2278 sortable = GTK_TREE_SORTABLE (store);
2280 gtk_tree_view_set_model (view, model);
2283 column = gtk_tree_view_column_new ();
2284 gtk_tree_view_column_set_title (column, _("What"));
2286 cell = gtk_cell_renderer_pixbuf_new ();
2287 gtk_tree_view_column_pack_start (column, cell, FALSE);
2288 gtk_tree_view_column_add_attribute (column, cell,
2289 "icon-name", COL_WHAT_ICON);
2291 cell = gtk_cell_renderer_text_new ();
2292 g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
2293 gtk_tree_view_column_pack_start (column, cell, TRUE);
2294 gtk_tree_view_column_add_attribute (column, cell,
2295 "text", COL_WHAT_TEXT);
2297 gtk_tree_view_append_column (view, column);
2299 /* set up treeview properties */
2300 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
2301 gtk_tree_view_set_show_expanders (view, FALSE);
2302 gtk_tree_view_set_level_indentation (view, 12);
2303 gtk_tree_view_expand_all (view);
2304 gtk_tree_view_set_row_separator_func (view, what_row_is_separator,
2308 for (i = 0; i < G_N_ELEMENTS (events); i++)
2310 gtk_tree_store_append (store, &iter, NULL);
2311 gtk_tree_store_set (store, &iter,
2312 COL_WHAT_TYPE, events[i].type,
2313 COL_WHAT_SUBTYPE, events[i].subtype,
2314 COL_WHAT_TEXT, events[i].text,
2315 COL_WHAT_ICON, events[i].icon,
2319 gtk_tree_model_iter_nth_child (model, &parent, NULL, 3);
2320 for (i = 0; i < G_N_ELEMENTS (call_events); i++)
2322 gtk_tree_store_append (store, &iter, &parent);
2323 gtk_tree_store_set (store, &iter,
2324 COL_WHAT_TYPE, call_events[i].type,
2325 COL_WHAT_SUBTYPE, call_events[i].subtype,
2326 COL_WHAT_TEXT, call_events[i].text,
2327 COL_WHAT_ICON, call_events[i].icon,
2331 gtk_tree_view_expand_all (view);
2333 /* select 'Anything' */
2334 if (gtk_tree_model_get_iter_first (model, &iter))
2335 gtk_tree_selection_select_iter (selection, &iter);
2337 /* set up signals */
2338 g_signal_connect (view, "test-collapse-row",
2339 G_CALLBACK (log_window_what_collapse_row_cb),
2341 g_signal_connect (selection, "changed",
2342 G_CALLBACK (log_window_what_changed_cb),
2345 g_object_unref (store);
2349 start_spinner (void)
2351 gtk_spinner_start (GTK_SPINNER (log_window->spinner));
2352 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2357 show_spinner (gpointer data)
2361 if (log_window == NULL)
2364 g_object_get (log_window->spinner, "active", &active, NULL);
2367 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2374 show_events (TplActionChain *chain,
2377 gtk_spinner_stop (GTK_SPINNER (log_window->spinner));
2378 gtk_notebook_set_current_page (GTK_NOTEBOOK (log_window->notebook),
2381 _tpl_action_chain_continue (chain);
2385 log_window_got_messages_for_date_cb (GObject *manager,
2386 GAsyncResult *result,
2389 Ctx *ctx = user_data;
2391 GtkTreeModel *model;
2395 GError *error = NULL;
2398 if (log_window == NULL)
2404 if (log_window->count != ctx->count)
2407 if (!tpl_log_manager_get_events_for_date_finish (TPL_LOG_MANAGER (manager),
2408 result, &events, &error))
2410 DEBUG ("Unable to retrieve messages for the selected date: %s. Aborting",
2412 g_error_free (error);
2416 for (l = events; l; l = l->next)
2418 TplEvent *event = l->data;
2419 gboolean append = TRUE;
2421 if (TPL_IS_CALL_EVENT (l->data)
2422 && ctx->event_mask & TPL_EVENT_MASK_CALL
2423 && ctx->event_mask != TPL_EVENT_MASK_ANY)
2425 TplCallEvent *call = l->data;
2429 if (ctx->subtype & EVENT_CALL_ALL)
2435 TplCallEndReason reason = tpl_call_event_get_end_reason (call);
2436 TplEntity *sender = tpl_event_get_sender (event);
2437 TplEntity *receiver = tpl_event_get_receiver (event);
2439 if (reason == TPL_CALL_END_REASON_NO_ANSWER)
2441 if (ctx->subtype & EVENT_CALL_MISSED)
2444 else if (ctx->subtype & EVENT_CALL_OUTGOING
2445 && tpl_entity_get_entity_type (sender) == TPL_ENTITY_SELF)
2449 else if (ctx->subtype & EVENT_CALL_INCOMING
2450 && tpl_entity_get_entity_type (receiver) == TPL_ENTITY_SELF)
2459 EmpathyMessage *msg = empathy_message_from_tpl_log_event (event);
2460 log_window_append_message (event, msg);
2461 g_object_unref (msg);
2464 g_object_unref (event);
2466 g_list_free (events);
2468 view = GTK_TREE_VIEW (log_window->treeview_events);
2469 model = gtk_tree_view_get_model (view);
2470 n = gtk_tree_model_iter_n_children (model, NULL) - 1;
2472 if (n >= 0 && gtk_tree_model_iter_nth_child (model, &iter, NULL, n))
2476 path = gtk_tree_model_get_path (model, &iter);
2477 gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0, 0);
2478 gtk_tree_path_free (path);
2484 _tpl_action_chain_continue (log_window->chain);
2488 get_events_for_date (TplActionChain *chain, gpointer user_data)
2490 Ctx *ctx = user_data;
2492 tpl_log_manager_get_events_for_date_async (ctx->window->log_manager,
2493 ctx->account, ctx->entity, ctx->event_mask,
2495 log_window_got_messages_for_date_cb,
2500 log_window_get_messages_for_dates (EmpathyLogWindow *window,
2503 GList *accounts, *targets, *acc, *targ, *l;
2504 TplEventTypeMask event_mask;
2505 EventSubtype subtype;
2506 GDate *date, *anytime, *separator;
2508 if (!log_window_get_selected (window,
2509 &accounts, &targets, NULL, &event_mask, &subtype))
2512 anytime = g_date_new_dmy (2, 1, -1);
2513 separator = g_date_new_dmy (1, 1, -1);
2515 _tpl_action_chain_clear (window->chain);
2518 for (acc = accounts, targ = targets;
2519 acc != NULL && targ != NULL;
2520 acc = acc->next, targ = targ->next)
2522 TpAccount *account = acc->data;
2523 TplEntity *target = targ->data;
2525 for (l = dates; l != NULL; l = l->next)
2530 if (g_date_compare (date, anytime) != 0)
2534 ctx = ctx_new (window, account, target, date, event_mask, subtype,
2536 _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
2540 GtkTreeView *view = GTK_TREE_VIEW (window->treeview_when);
2541 GtkTreeModel *model = gtk_tree_view_get_model (view);
2546 for (next = gtk_tree_model_get_iter_first (model, &iter);
2548 next = gtk_tree_model_iter_next (model, &iter))
2552 gtk_tree_model_get (model, &iter,
2556 if (g_date_compare (d, anytime) != 0 &&
2557 g_date_compare (d, separator) != 0)
2559 ctx = ctx_new (window, account, target, d,
2560 event_mask, subtype, window->count);
2561 _tpl_action_chain_append (window->chain, get_events_for_date, ctx);
2569 g_timeout_add (1000, show_spinner, NULL);
2570 _tpl_action_chain_append (window->chain, show_events, NULL);
2571 _tpl_action_chain_start (window->chain);
2573 g_list_free_full (accounts, g_object_unref);
2574 g_list_free_full (targets, g_object_unref);
2575 g_date_free (separator);
2576 g_date_free (anytime);
2580 log_manager_got_dates_cb (GObject *manager,
2581 GAsyncResult *result,
2584 Ctx *ctx = user_data;
2586 GtkTreeModel *model;
2587 GtkTreeSelection *selection;
2588 GtkListStore *store;
2592 GError *error = NULL;
2594 if (log_window == NULL)
2597 if (log_window->count != ctx->count)
2600 if (!tpl_log_manager_get_dates_finish (TPL_LOG_MANAGER (manager),
2601 result, &dates, &error))
2603 DEBUG ("Unable to retrieve messages' dates: %s. Aborting",
2608 view = GTK_TREE_VIEW (log_window->treeview_when);
2609 model = gtk_tree_view_get_model (view);
2610 store = GTK_LIST_STORE (model);
2611 selection = gtk_tree_view_get_selection (view);
2613 for (l = dates; l != NULL; l = l->next)
2615 GDate *date = l->data;
2617 /* Add the date if it's not already there */
2618 has_element = FALSE;
2619 gtk_tree_model_foreach (model, model_has_date, date);
2622 gchar *text = format_date_for_display (date);
2624 gtk_list_store_append (store, &iter);
2625 gtk_list_store_set (store, &iter,
2626 COL_WHEN_DATE, date,
2627 COL_WHEN_TEXT, text,
2628 COL_WHEN_ICON, CALENDAR_ICON,
2635 if (gtk_tree_model_get_iter_first (model, &iter))
2637 gchar *separator = NULL;
2639 if (gtk_tree_model_iter_next (model, &iter))
2641 gtk_tree_model_get (model, &iter,
2642 COL_WHEN_TEXT, &separator,
2646 if (g_strcmp0 (separator, "separator") != 0)
2648 gtk_list_store_prepend (store, &iter);
2649 gtk_list_store_set (store, &iter,
2650 COL_WHEN_DATE, g_date_new_dmy (1, 1, -1),
2651 COL_WHEN_TEXT, "separator",
2654 gtk_list_store_prepend (store, &iter);
2655 gtk_list_store_set (store, &iter,
2656 COL_WHEN_DATE, g_date_new_dmy (2, 1, -1),
2657 COL_WHEN_TEXT, _("Anytime"),
2662 g_list_free_full (dates, g_free);
2665 _tpl_action_chain_continue (log_window->chain);
2669 select_first_date (TplActionChain *chain, gpointer user_data)
2672 GtkTreeModel *model;
2673 GtkTreeSelection *selection;
2676 view = GTK_TREE_VIEW (log_window->treeview_when);
2677 model = gtk_tree_view_get_model (view);
2678 selection = gtk_tree_view_get_selection (view);
2680 /* Show messages of the most recent date */
2681 if (gtk_tree_model_iter_nth_child (model, &iter, NULL, 2))
2682 gtk_tree_selection_select_iter (selection, &iter);
2684 _tpl_action_chain_continue (log_window->chain);
2688 get_dates_for_entity (TplActionChain *chain, gpointer user_data)
2690 Ctx *ctx = user_data;
2692 tpl_log_manager_get_dates_async (ctx->window->log_manager,
2693 ctx->account, ctx->entity, ctx->event_mask,
2694 log_manager_got_dates_cb, ctx);
2698 log_window_chats_get_messages (EmpathyLogWindow *window,
2699 gboolean force_get_dates)
2701 GList *accounts, *targets, *dates;
2702 TplEventTypeMask event_mask;
2704 GtkTreeModel *model;
2705 GtkListStore *store;
2706 GtkTreeSelection *selection;
2708 if (!log_window_get_selected (window, &accounts, &targets,
2709 &dates, &event_mask, NULL))
2712 view = GTK_TREE_VIEW (window->treeview_when);
2713 selection = gtk_tree_view_get_selection (view);
2714 model = gtk_tree_view_get_model (view);
2715 store = GTK_LIST_STORE (model);
2717 /* Clear all current messages shown in the textview */
2718 gtk_tree_store_clear (window->store_events);
2720 _tpl_action_chain_clear (window->chain);
2723 /* If there's a search use the returned hits */
2724 if (window->hits != NULL)
2726 if (force_get_dates)
2728 g_signal_handlers_block_by_func (selection,
2729 log_window_when_changed_cb,
2732 gtk_list_store_clear (store);
2734 g_signal_handlers_unblock_by_func (selection,
2735 log_window_when_changed_cb,
2738 populate_dates_from_search_hits (accounts, targets);
2742 populate_events_from_search_hits (accounts, targets, dates);
2745 /* Either use the supplied date or get the last */
2746 else if (force_get_dates || dates == NULL)
2750 g_signal_handlers_block_by_func (selection,
2751 log_window_when_changed_cb,
2754 gtk_list_store_clear (store);
2756 g_signal_handlers_unblock_by_func (selection,
2757 log_window_when_changed_cb,
2760 /* Get a list of dates and show them on the treeview */
2761 for (targ = targets, acc = accounts;
2762 targ != NULL && acc != NULL;
2763 targ = targ->next, acc = acc->next)
2765 TpAccount *account = acc->data;
2766 TplEntity *target = targ->data;
2767 Ctx *ctx = ctx_new (window, account, target, NULL, event_mask, 0,
2770 _tpl_action_chain_append (window->chain, get_dates_for_entity, ctx);
2772 _tpl_action_chain_append (window->chain, select_first_date, NULL);
2773 _tpl_action_chain_start (window->chain);
2777 /* Show messages of the selected date */
2778 log_window_get_messages_for_dates (window, dates);
2781 g_list_free_full (accounts, g_object_unref);
2782 g_list_free_full (targets, g_object_unref);
2783 g_list_free_full (dates, (GFreeFunc) g_date_free);
2787 EmpathyAccountChooserFilterResultCallback callback;
2789 } FilterCallbackData;
2792 got_entities (GObject *manager,
2793 GAsyncResult *result,
2796 FilterCallbackData *data = user_data;
2798 GError *error = NULL;
2800 if (!tpl_log_manager_get_entities_finish (TPL_LOG_MANAGER (manager),
2801 result, &entities, &error))
2803 DEBUG ("Could not get entities: %s", error->message);
2804 g_error_free (error);
2805 data->callback (FALSE, data->user_data);
2809 data->callback (entities != NULL, data->user_data);
2811 g_list_free_full (entities, g_object_unref);
2814 g_slice_free (FilterCallbackData, data);
2818 empathy_account_chooser_filter_has_logs (TpAccount *account,
2819 EmpathyAccountChooserFilterResultCallback callback,
2820 gpointer callback_data,
2823 TplLogManager *manager = tpl_log_manager_dup_singleton ();
2824 FilterCallbackData *cb_data = g_slice_new0 (FilterCallbackData);
2826 cb_data->callback = callback;
2827 cb_data->user_data = callback_data;
2829 tpl_log_manager_get_entities_async (manager, account, got_entities, cb_data);
2831 g_object_unref (manager);
2835 log_window_logger_clear_account_cb (TpProxy *proxy,
2836 const GError *error,
2838 GObject *weak_object)
2840 EmpathyLogWindow *window = user_data;
2843 g_warning ("Error when clearing logs: %s", error->message);
2845 /* Refresh the log viewer so the logs are cleared if the account
2846 * has been deleted */
2847 gtk_tree_store_clear (window->store_events);
2848 log_window_who_populate (window);
2850 /* Re-filter the account chooser so the accounts without logs get greyed out */
2851 empathy_account_chooser_set_filter (
2852 EMPATHY_ACCOUNT_CHOOSER (window->account_chooser),
2853 empathy_account_chooser_filter_has_logs, NULL);
2857 log_window_clear_logs_chooser_select_account (EmpathyAccountChooser *chooser,
2858 EmpathyLogWindow *window)
2860 EmpathyAccountChooser *account_chooser;
2862 account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser);
2864 empathy_account_chooser_set_account (chooser,
2865 empathy_account_chooser_get_account (account_chooser));
2869 log_window_delete_menu_clicked_cb (GtkMenuItem *menuitem,
2870 EmpathyLogWindow *window)
2872 GtkWidget *dialog, *content_area, *hbox, *label;
2873 EmpathyAccountChooser *account_chooser;
2877 GError *error = NULL;
2879 account_chooser = (EmpathyAccountChooser *) empathy_account_chooser_new ();
2880 empathy_account_chooser_set_has_all_option (account_chooser, TRUE);
2881 empathy_account_chooser_set_filter (account_chooser,
2882 empathy_account_chooser_filter_has_logs, NULL);
2884 /* Select the same account as in the history window */
2885 if (empathy_account_chooser_is_ready (account_chooser))
2886 log_window_clear_logs_chooser_select_account (account_chooser, window);
2888 g_signal_connect (account_chooser, "ready",
2889 G_CALLBACK (log_window_clear_logs_chooser_select_account), window);
2891 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window->window),
2892 GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING,
2894 _("Are you sure you want to delete all logs of previous conversations?"));
2896 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
2897 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2898 _("Clear All"), GTK_RESPONSE_APPLY,
2901 content_area = gtk_message_dialog_get_message_area (
2902 GTK_MESSAGE_DIALOG (dialog));
2904 hbox = gtk_hbox_new (FALSE, 6);
2905 label = gtk_label_new (_("Delete from:"));
2906 gtk_box_pack_start (GTK_BOX (hbox), label,
2908 gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (account_chooser),
2910 gtk_box_pack_start (GTK_BOX (content_area), hbox,
2913 gtk_widget_show_all (hbox);
2915 response_id = gtk_dialog_run (GTK_DIALOG (dialog));
2917 if (response_id != GTK_RESPONSE_APPLY)
2920 bus = tp_dbus_daemon_dup (&error);
2923 g_warning ("Could not delete logs: %s", error->message);
2924 g_error_free (error);
2928 logger = g_object_new (TP_TYPE_PROXY,
2929 "bus-name", "org.freedesktop.Telepathy.Logger",
2930 "object-path", "/org/freedesktop/Telepathy/Logger",
2933 g_object_unref (bus);
2935 tp_proxy_add_interface_by_id (logger, EMP_IFACE_QUARK_LOGGER);
2937 if (empathy_account_chooser_has_all_selected (account_chooser))
2939 DEBUG ("Deleting logs for all the accounts");
2941 emp_cli_logger_call_clear (logger, -1,
2942 log_window_logger_clear_account_cb,
2943 window, NULL, G_OBJECT (window->window));
2949 account = empathy_account_chooser_get_account (account_chooser);
2951 DEBUG ("Deleting logs for %s", tp_proxy_get_object_path (account));
2953 emp_cli_logger_call_clear_account (logger, -1,
2954 tp_proxy_get_object_path (account),
2955 log_window_logger_clear_account_cb,
2956 window, NULL, G_OBJECT (window->window));
2959 g_object_unref (logger);
2961 gtk_widget_destroy (dialog);