]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-log-window.c
account-chooser.c: add a 'ready' signal
[empathy.git] / libempathy-gtk / empathy-log-window.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2006-2007 Imendio AB
4  * Copyright (C) 2007-2008 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301  USA
20  *
21  * Authors: Martyn Russell <martyn@imendio.com>
22  *          Xavier Claessens <xclaesse@gmail.com>
23  */
24
25 #include "config.h"
26
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include <glib/gi18n-lib.h>
31 #include <gtk/gtk.h>
32
33 #include <telepathy-glib/account-manager.h>
34
35 #include <libempathy/empathy-log-manager.h>
36 #include <libempathy/empathy-chatroom-manager.h>
37 #include <libempathy/empathy-chatroom.h>
38 #include <libempathy/empathy-message.h>
39 #include <libempathy/empathy-utils.h>
40 #include <libempathy/empathy-time.h>
41
42 #include "empathy-log-window.h"
43 #include "empathy-account-chooser.h"
44 #include "empathy-chat-view.h"
45 #include "empathy-theme-manager.h"
46 #include "empathy-ui-utils.h"
47
48 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
49 #include <libempathy/empathy-debug.h>
50
51 typedef struct {
52         GtkWidget         *window;
53
54         GtkWidget         *notebook;
55
56         GtkWidget         *entry_find;
57         GtkWidget         *button_find;
58         GtkWidget         *treeview_find;
59         GtkWidget         *scrolledwindow_find;
60         EmpathyChatView    *chatview_find;
61         GtkWidget         *button_previous;
62         GtkWidget         *button_next;
63
64         GtkWidget         *vbox_chats;
65         GtkWidget         *account_chooser_chats;
66         GtkWidget         *entry_chats;
67         GtkWidget         *calendar_chats;
68         GtkWidget         *treeview_chats;
69         GtkWidget         *scrolledwindow_chats;
70         EmpathyChatView    *chatview_chats;
71
72         gchar             *last_find;
73
74         EmpathyLogManager *log_manager;
75 } EmpathyLogWindow;
76
77 static void     log_window_destroy_cb                      (GtkWidget        *widget,
78                                                             EmpathyLogWindow *window);
79 static void     log_window_entry_find_changed_cb           (GtkWidget        *entry,
80                                                             EmpathyLogWindow *window);
81 static void     log_window_find_changed_cb                 (GtkTreeSelection *selection,
82                                                             EmpathyLogWindow *window);
83 static void     log_window_find_populate                   (EmpathyLogWindow *window,
84                                                             const gchar      *search_criteria);
85 static void     log_window_find_setup                      (EmpathyLogWindow *window);
86 static void     log_window_button_find_clicked_cb          (GtkWidget        *widget,
87                                                             EmpathyLogWindow *window);
88 static void     log_window_button_next_clicked_cb          (GtkWidget        *widget,
89                                                             EmpathyLogWindow *window);
90 static void     log_window_button_previous_clicked_cb      (GtkWidget        *widget,
91                                                             EmpathyLogWindow *window);
92 static void     log_window_chats_changed_cb                (GtkTreeSelection *selection,
93                                                             EmpathyLogWindow *window);
94 static void     log_window_chats_populate                  (EmpathyLogWindow *window);
95 static void     log_window_chats_setup                     (EmpathyLogWindow *window);
96 static void     log_window_chats_accounts_changed_cb       (GtkWidget        *combobox,
97                                                             EmpathyLogWindow *window);
98 static void     log_window_chats_set_selected              (EmpathyLogWindow *window,
99                                                             TpAccount        *account,
100                                                             const gchar      *chat_id,
101                                                             gboolean          is_chatroom);
102 static gboolean log_window_chats_get_selected              (EmpathyLogWindow *window,
103                                                             TpAccount       **account,
104                                                             gchar           **chat_id,
105                                                             gboolean         *is_chatroom);
106 static void     log_window_chats_get_messages              (EmpathyLogWindow *window,
107                                                             const gchar      *date_to_show);
108 static void     log_window_calendar_chats_day_selected_cb  (GtkWidget        *calendar,
109                                                             EmpathyLogWindow *window);
110 static void     log_window_calendar_chats_month_changed_cb (GtkWidget        *calendar,
111                                                             EmpathyLogWindow *window);
112 static void     log_window_entry_chats_changed_cb          (GtkWidget        *entry,
113                                                             EmpathyLogWindow *window);
114 static void     log_window_entry_chats_activate_cb         (GtkWidget        *entry,
115                                                             EmpathyLogWindow *window);
116
117 enum {
118         COL_FIND_ACCOUNT_ICON,
119         COL_FIND_ACCOUNT_NAME,
120         COL_FIND_ACCOUNT,
121         COL_FIND_CHAT_NAME,
122         COL_FIND_CHAT_ID,
123         COL_FIND_IS_CHATROOM,
124         COL_FIND_DATE,
125         COL_FIND_DATE_READABLE,
126         COL_FIND_COUNT
127 };
128
129 enum {
130         COL_CHAT_ICON,
131         COL_CHAT_NAME,
132         COL_CHAT_ACCOUNT,
133         COL_CHAT_ID,
134         COL_CHAT_IS_CHATROOM,
135         COL_CHAT_COUNT
136 };
137
138 static void
139 account_manager_prepared_cb (GObject *source_object,
140                              GAsyncResult *result,
141                              gpointer user_data)
142 {
143         TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
144         EmpathyLogWindow *window = user_data;
145         guint account_num;
146         GList *accounts;
147         GError *error = NULL;
148
149         if (!tp_account_manager_prepare_finish (account_manager, result, &error)) {
150                 DEBUG ("Failed to prepare account manager: %s", error->message);
151                 g_error_free (error);
152                 return;
153         }
154
155         accounts = tp_account_manager_get_valid_accounts (account_manager);
156         account_num = g_list_length (accounts);
157         g_list_free (accounts);
158
159         if (account_num > 1) {
160                 gtk_widget_show (window->vbox_chats);
161                 gtk_widget_show (window->account_chooser_chats);
162         } else {
163                 gtk_widget_hide (window->vbox_chats);
164                 gtk_widget_hide (window->account_chooser_chats);
165         }
166 }
167
168 GtkWidget *
169 empathy_log_window_show (TpAccount  *account,
170                         const gchar *chat_id,
171                         gboolean     is_chatroom,
172                         GtkWindow   *parent)
173 {
174         static EmpathyLogWindow *window = NULL;
175         EmpathyAccountChooser   *account_chooser;
176         TpAccountManager        *account_manager;
177         GtkBuilder             *gui;
178         gchar                  *filename;
179
180         if (window) {
181                 gtk_window_present (GTK_WINDOW (window->window));
182
183                 if (account && chat_id) {
184                         gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1);
185                         log_window_chats_set_selected (window, account,
186                                                        chat_id, is_chatroom);
187                 }
188
189                 return window->window;
190         }
191
192         window = g_new0 (EmpathyLogWindow, 1);
193         window->log_manager = empathy_log_manager_dup_singleton ();
194
195         filename = empathy_file_lookup ("empathy-log-window.ui",
196                                         "libempathy-gtk");
197         gui = empathy_builder_get_file (filename,
198                                        "log_window", &window->window,
199                                        "notebook", &window->notebook,
200                                        "entry_find", &window->entry_find,
201                                        "button_find", &window->button_find,
202                                        "treeview_find", &window->treeview_find,
203                                        "scrolledwindow_find", &window->scrolledwindow_find,
204                                        "button_previous", &window->button_previous,
205                                        "button_next", &window->button_next,
206                                        "entry_chats", &window->entry_chats,
207                                        "calendar_chats", &window->calendar_chats,
208                                        "vbox_chats", &window->vbox_chats,
209                                        "treeview_chats", &window->treeview_chats,
210                                        "scrolledwindow_chats", &window->scrolledwindow_chats,
211                                        NULL);
212         g_free (filename);
213
214         empathy_builder_connect (gui, window,
215                               "log_window", "destroy", log_window_destroy_cb,
216                               "entry_find", "changed", log_window_entry_find_changed_cb,
217                               "button_previous", "clicked", log_window_button_previous_clicked_cb,
218                               "button_next", "clicked", log_window_button_next_clicked_cb,
219                               "button_find", "clicked", log_window_button_find_clicked_cb,
220                               "entry_chats", "changed", log_window_entry_chats_changed_cb,
221                               "entry_chats", "activate", log_window_entry_chats_activate_cb,
222                               NULL);
223
224         g_object_unref (gui);
225
226         g_object_add_weak_pointer (G_OBJECT (window->window),
227                                    (gpointer) &window);
228
229         /* We set this up here so we can block it when needed. */
230         g_signal_connect (window->calendar_chats, "day-selected",
231                           G_CALLBACK (log_window_calendar_chats_day_selected_cb),
232                           window);
233         g_signal_connect (window->calendar_chats, "month-changed",
234                           G_CALLBACK (log_window_calendar_chats_month_changed_cb),
235                           window);
236
237         /* Configure Search EmpathyChatView */
238         window->chatview_find = empathy_theme_manager_create_view (empathy_theme_manager_get ());
239         gtk_container_add (GTK_CONTAINER (window->scrolledwindow_find),
240                            GTK_WIDGET (window->chatview_find));
241         gtk_widget_show (GTK_WIDGET (window->chatview_find));
242
243         /* Configure Contacts EmpathyChatView */
244         window->chatview_chats = empathy_theme_manager_create_view (empathy_theme_manager_get ());
245         gtk_container_add (GTK_CONTAINER (window->scrolledwindow_chats),
246                            GTK_WIDGET (window->chatview_chats));
247         gtk_widget_show (GTK_WIDGET (window->chatview_chats));
248
249         /* Account chooser for chats */
250         window->account_chooser_chats = empathy_account_chooser_new ();
251         account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats);
252
253         gtk_box_pack_start (GTK_BOX (window->vbox_chats),
254                             window->account_chooser_chats,
255                             FALSE, TRUE, 0);
256
257         g_signal_connect (window->account_chooser_chats, "changed",
258                           G_CALLBACK (log_window_chats_accounts_changed_cb),
259                           window);
260
261         /* Populate */
262         account_manager = tp_account_manager_dup ();
263         tp_account_manager_prepare_async (account_manager, NULL,
264                                           account_manager_prepared_cb, window);
265         g_object_unref (account_manager);
266
267         /* Search List */
268         log_window_find_setup (window);
269
270         /* Contacts */
271         log_window_chats_setup (window);
272         log_window_chats_populate (window);
273
274         /* Select chat */
275         if (account && chat_id) {
276                 gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1);
277                 log_window_chats_set_selected (window, account,
278                                                chat_id, is_chatroom);
279         }
280
281         if (parent) {
282                 gtk_window_set_transient_for (GTK_WINDOW (window->window),
283                                               GTK_WINDOW (parent));
284         }
285
286         gtk_widget_show (window->window);
287
288         return window->window;
289 }
290
291 static void
292 log_window_destroy_cb (GtkWidget       *widget,
293                        EmpathyLogWindow *window)
294 {
295         g_free (window->last_find);
296         g_object_unref (window->log_manager);
297
298         g_free (window);
299 }
300
301 /*
302  * Search code.
303  */
304 static void
305 log_window_entry_find_changed_cb (GtkWidget       *entry,
306                                   EmpathyLogWindow *window)
307 {
308         const gchar *str;
309         gboolean     is_sensitive = TRUE;
310
311         str = gtk_entry_get_text (GTK_ENTRY (window->entry_find));
312
313         is_sensitive &= !EMP_STR_EMPTY (str);
314         is_sensitive &=
315                 !window->last_find ||
316                 (window->last_find && strcmp (window->last_find, str) != 0);
317
318         gtk_widget_set_sensitive (window->button_find, is_sensitive);
319 }
320
321 static void
322 log_window_find_changed_cb (GtkTreeSelection *selection,
323                             EmpathyLogWindow  *window)
324 {
325         GtkTreeView   *view;
326         GtkTreeModel  *model;
327         GtkTreeIter    iter;
328         TpAccount     *account;
329         gchar         *chat_id;
330         gboolean       is_chatroom;
331         gchar         *date;
332         EmpathyMessage *message;
333         GList         *messages;
334         GList         *l;
335         gboolean       can_do_previous;
336         gboolean       can_do_next;
337
338         /* Get selected information */
339         view = GTK_TREE_VIEW (window->treeview_find);
340         model = gtk_tree_view_get_model (view);
341
342         if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
343                 gtk_widget_set_sensitive (window->button_previous, FALSE);
344                 gtk_widget_set_sensitive (window->button_next, FALSE);
345
346                 empathy_chat_view_clear (window->chatview_find);
347
348                 return;
349         }
350
351         gtk_widget_set_sensitive (window->button_previous, TRUE);
352         gtk_widget_set_sensitive (window->button_next, TRUE);
353
354         gtk_tree_model_get (model, &iter,
355                             COL_FIND_ACCOUNT, &account,
356                             COL_FIND_CHAT_ID, &chat_id,
357                             COL_FIND_IS_CHATROOM, &is_chatroom,
358                             COL_FIND_DATE, &date,
359                             -1);
360
361         /* Clear all current messages shown in the textview */
362         empathy_chat_view_clear (window->chatview_find);
363
364         /* Turn off scrolling temporarily */
365         empathy_chat_view_scroll (window->chatview_find, FALSE);
366
367         /* Get messages */
368         messages = empathy_log_manager_get_messages_for_date (window->log_manager,
369                                                               account,
370                                                               chat_id,
371                                                               is_chatroom,
372                                                               date);
373         g_object_unref (account);
374         g_free (date);
375         g_free (chat_id);
376
377         for (l = messages; l; l = l->next) {
378                 message = l->data;
379                 empathy_chat_view_append_message (window->chatview_find, message);
380                 g_object_unref (message);
381         }
382         g_list_free (messages);
383
384         /* Scroll to the most recent messages */
385         empathy_chat_view_scroll (window->chatview_find, TRUE);
386
387         /* Highlight and find messages */
388         empathy_chat_view_highlight (window->chatview_find,
389                                     window->last_find);
390         empathy_chat_view_find_next (window->chatview_find,
391                                     window->last_find,
392                                     TRUE);
393         empathy_chat_view_find_abilities (window->chatview_find,
394                                          window->last_find,
395                                          &can_do_previous,
396                                          &can_do_next);
397         gtk_widget_set_sensitive (window->button_previous, can_do_previous);
398         gtk_widget_set_sensitive (window->button_next, can_do_next);
399         gtk_widget_set_sensitive (window->button_find, FALSE);
400 }
401
402 static void
403 log_window_find_populate (EmpathyLogWindow *window,
404                           const gchar     *search_criteria)
405 {
406         GList              *hits, *l;
407
408         GtkTreeView        *view;
409         GtkTreeModel       *model;
410         GtkTreeSelection   *selection;
411         GtkListStore       *store;
412         GtkTreeIter         iter;
413
414         view = GTK_TREE_VIEW (window->treeview_find);
415         model = gtk_tree_view_get_model (view);
416         selection = gtk_tree_view_get_selection (view);
417         store = GTK_LIST_STORE (model);
418
419         empathy_chat_view_clear (window->chatview_find);
420
421         gtk_list_store_clear (store);
422
423         if (EMP_STR_EMPTY (search_criteria)) {
424                 /* Just clear the search. */
425                 return;
426         }
427
428         hits = empathy_log_manager_search_new (window->log_manager, search_criteria);
429
430         for (l = hits; l; l = l->next) {
431                 EmpathyLogSearchHit *hit;
432                 const gchar         *account_name;
433                 const gchar         *account_icon;
434                 gchar               *date_readable;
435
436                 hit = l->data;
437
438                 /* Protect against invalid data (corrupt or old log files. */
439                 if (!hit->account || !hit->chat_id) {
440                         continue;
441                 }
442
443                 date_readable = empathy_log_manager_get_date_readable (hit->date);
444                 account_name = tp_account_get_display_name (hit->account);
445                 account_icon = tp_account_get_icon_name (hit->account);
446
447                 gtk_list_store_append (store, &iter);
448                 gtk_list_store_set (store, &iter,
449                                     COL_FIND_ACCOUNT_ICON, account_icon,
450                                     COL_FIND_ACCOUNT_NAME, account_name,
451                                     COL_FIND_ACCOUNT, hit->account,
452                                     COL_FIND_CHAT_NAME, hit->chat_id, /* FIXME */
453                                     COL_FIND_CHAT_ID, hit->chat_id,
454                                     COL_FIND_IS_CHATROOM, hit->is_chatroom,
455                                     COL_FIND_DATE, hit->date,
456                                     COL_FIND_DATE_READABLE, date_readable,
457                                     -1);
458
459                 g_free (date_readable);
460
461                 /* FIXME: Update COL_FIND_CHAT_NAME */
462                 if (hit->is_chatroom) {
463                 } else {
464                 }
465         }
466
467         if (hits) {
468                 empathy_log_manager_search_free (hits);
469         }
470 }
471
472 static void
473 log_window_find_setup (EmpathyLogWindow *window)
474 {
475         GtkTreeView       *view;
476         GtkTreeModel      *model;
477         GtkTreeSelection  *selection;
478         GtkTreeSortable   *sortable;
479         GtkTreeViewColumn *column;
480         GtkListStore      *store;
481         GtkCellRenderer   *cell;
482         gint               offset;
483
484         view = GTK_TREE_VIEW (window->treeview_find);
485         selection = gtk_tree_view_get_selection (view);
486
487         /* New store */
488         store = gtk_list_store_new (COL_FIND_COUNT,
489                                     G_TYPE_STRING,          /* account icon name */
490                                     G_TYPE_STRING,          /* account name */
491                                     TP_TYPE_ACCOUNT,        /* account */
492                                     G_TYPE_STRING,          /* chat name */
493                                     G_TYPE_STRING,          /* chat id */
494                                     G_TYPE_BOOLEAN,         /* is chatroom */
495                                     G_TYPE_STRING,          /* date */
496                                     G_TYPE_STRING);         /* date_readable */
497
498         model = GTK_TREE_MODEL (store);
499         sortable = GTK_TREE_SORTABLE (store);
500
501         gtk_tree_view_set_model (view, model);
502
503         /* New column */
504         column = gtk_tree_view_column_new ();
505
506         cell = gtk_cell_renderer_pixbuf_new ();
507         gtk_tree_view_column_pack_start (column, cell, FALSE);
508         gtk_tree_view_column_add_attribute (column, cell,
509                                             "icon-name",
510                                             COL_FIND_ACCOUNT_ICON);
511
512         cell = gtk_cell_renderer_text_new ();
513         gtk_tree_view_column_pack_start (column, cell, TRUE);
514         gtk_tree_view_column_add_attribute (column, cell,
515                                             "text",
516                                             COL_FIND_ACCOUNT_NAME);
517
518         gtk_tree_view_column_set_title (column, _("Account"));
519         gtk_tree_view_append_column (view, column);
520
521         gtk_tree_view_column_set_resizable (column, TRUE);
522         gtk_tree_view_column_set_clickable (column, TRUE);
523
524         cell = gtk_cell_renderer_text_new ();
525         offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Conversation"),
526                                                               cell, "text", COL_FIND_CHAT_NAME,
527                                                               NULL);
528
529         column = gtk_tree_view_get_column (view, offset - 1);
530         gtk_tree_view_column_set_sort_column_id (column, COL_FIND_CHAT_NAME);
531         gtk_tree_view_column_set_resizable (column, TRUE);
532         gtk_tree_view_column_set_clickable (column, TRUE);
533
534         cell = gtk_cell_renderer_text_new ();
535         offset = gtk_tree_view_insert_column_with_attributes (view, -1, _("Date"),
536                                                               cell, "text", COL_FIND_DATE_READABLE,
537                                                               NULL);
538
539         column = gtk_tree_view_get_column (view, offset - 1);
540         gtk_tree_view_column_set_sort_column_id (column, COL_FIND_DATE);
541         gtk_tree_view_column_set_resizable (column, TRUE);
542         gtk_tree_view_column_set_clickable (column, TRUE);
543
544         /* Set up treeview properties */
545         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
546         gtk_tree_sortable_set_sort_column_id (sortable,
547                                               COL_FIND_DATE,
548                                               GTK_SORT_ASCENDING);
549
550         /* Set up signals */
551         g_signal_connect (selection, "changed",
552                           G_CALLBACK (log_window_find_changed_cb),
553                           window);
554
555         g_object_unref (store);
556 }
557
558 static void
559 log_window_button_find_clicked_cb (GtkWidget       *widget,
560                                    EmpathyLogWindow *window)
561 {
562         const gchar *str;
563
564         str = gtk_entry_get_text (GTK_ENTRY (window->entry_find));
565
566         /* Don't find the same crap again */
567         if (window->last_find && strcmp (window->last_find, str) == 0) {
568                 return;
569         }
570
571         g_free (window->last_find);
572         window->last_find = g_strdup (str);
573
574         log_window_find_populate (window, str);
575 }
576
577 static void
578 log_window_button_next_clicked_cb (GtkWidget       *widget,
579                                    EmpathyLogWindow *window)
580 {
581         if (window->last_find) {
582                 gboolean can_do_previous;
583                 gboolean can_do_next;
584
585                 empathy_chat_view_find_next (window->chatview_find,
586                                             window->last_find,
587                                             FALSE);
588                 empathy_chat_view_find_abilities (window->chatview_find,
589                                                  window->last_find,
590                                                  &can_do_previous,
591                                                  &can_do_next);
592                 gtk_widget_set_sensitive (window->button_previous, can_do_previous);
593                 gtk_widget_set_sensitive (window->button_next, can_do_next);
594         }
595 }
596
597 static void
598 log_window_button_previous_clicked_cb (GtkWidget       *widget,
599                                        EmpathyLogWindow *window)
600 {
601         if (window->last_find) {
602                 gboolean can_do_previous;
603                 gboolean can_do_next;
604
605                 empathy_chat_view_find_previous (window->chatview_find,
606                                                 window->last_find,
607                                                 FALSE);
608                 empathy_chat_view_find_abilities (window->chatview_find,
609                                                  window->last_find,
610                                                  &can_do_previous,
611                                                  &can_do_next);
612                 gtk_widget_set_sensitive (window->button_previous, can_do_previous);
613                 gtk_widget_set_sensitive (window->button_next, can_do_next);
614         }
615 }
616
617 /*
618  * Chats Code
619  */
620
621 static void
622 log_window_chats_changed_cb (GtkTreeSelection *selection,
623                              EmpathyLogWindow  *window)
624 {
625         /* Use last date by default */
626         gtk_calendar_clear_marks (GTK_CALENDAR (window->calendar_chats));
627
628         log_window_chats_get_messages (window, NULL);
629 }
630
631 static void
632 log_window_chats_populate (EmpathyLogWindow *window)
633 {
634         EmpathyAccountChooser *account_chooser;
635         TpAccount             *account;
636         GList                *chats, *l;
637
638         GtkTreeView          *view;
639         GtkTreeModel         *model;
640         GtkTreeSelection     *selection;
641         GtkListStore         *store;
642         GtkTreeIter           iter;
643
644         account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats);
645         account = empathy_account_chooser_dup_account (account_chooser);
646
647         view = GTK_TREE_VIEW (window->treeview_chats);
648         model = gtk_tree_view_get_model (view);
649         selection = gtk_tree_view_get_selection (view);
650         store = GTK_LIST_STORE (model);
651
652         if (account == NULL) {
653                 gtk_list_store_clear (store);
654                 return;
655         }
656
657         /* Block signals to stop the logs being retrieved prematurely */
658         g_signal_handlers_block_by_func (selection,
659                                          log_window_chats_changed_cb,
660                                          window);
661
662         gtk_list_store_clear (store);
663
664         chats = empathy_log_manager_get_chats (window->log_manager, account);
665         for (l = chats; l; l = l->next) {
666                 EmpathyLogSearchHit *hit;
667
668                 hit = l->data;
669
670                 gtk_list_store_append (store, &iter);
671                 gtk_list_store_set (store, &iter,
672                                     COL_CHAT_ICON, "empathy-available", /* FIXME */
673                                     COL_CHAT_NAME, hit->chat_id,
674                                     COL_CHAT_ACCOUNT, account,
675                                     COL_CHAT_ID, hit->chat_id,
676                                     COL_CHAT_IS_CHATROOM, hit->is_chatroom,
677                                     -1);
678
679                 /* FIXME: Update COL_CHAT_ICON/NAME */
680                 if (hit->is_chatroom) {
681                 } else {
682                 }
683         }
684         empathy_log_manager_search_free (chats);
685
686         /* Unblock signals */
687         g_signal_handlers_unblock_by_func (selection,
688                                            log_window_chats_changed_cb,
689                                            window);
690
691
692         g_object_unref (account);
693 }
694
695 static void
696 log_window_chats_setup (EmpathyLogWindow *window)
697 {
698         GtkTreeView       *view;
699         GtkTreeModel      *model;
700         GtkTreeSelection  *selection;
701         GtkTreeSortable   *sortable;
702         GtkTreeViewColumn *column;
703         GtkListStore      *store;
704         GtkCellRenderer   *cell;
705
706         view = GTK_TREE_VIEW (window->treeview_chats);
707         selection = gtk_tree_view_get_selection (view);
708
709         /* new store */
710         store = gtk_list_store_new (COL_CHAT_COUNT,
711                                     G_TYPE_STRING,        /* icon */
712                                     G_TYPE_STRING,        /* name */
713                                     TP_TYPE_ACCOUNT,      /* account */
714                                     G_TYPE_STRING,        /* id */
715                                     G_TYPE_BOOLEAN);      /* is chatroom */
716
717         model = GTK_TREE_MODEL (store);
718         sortable = GTK_TREE_SORTABLE (store);
719
720         gtk_tree_view_set_model (view, model);
721
722         /* new column */
723         column = gtk_tree_view_column_new ();
724
725         cell = gtk_cell_renderer_pixbuf_new ();
726         gtk_tree_view_column_pack_start (column, cell, FALSE);
727         gtk_tree_view_column_add_attribute (column, cell,
728                                             "icon-name",
729                                             COL_CHAT_ICON);
730
731         cell = gtk_cell_renderer_text_new ();
732         g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
733         gtk_tree_view_column_pack_start (column, cell, TRUE);
734         gtk_tree_view_column_add_attribute (column, cell,
735                                             "text",
736                                             COL_CHAT_NAME);
737
738         gtk_tree_view_append_column (view, column);
739
740         /* set up treeview properties */
741         gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
742         gtk_tree_sortable_set_sort_column_id (sortable,
743                                               COL_CHAT_NAME,
744                                               GTK_SORT_ASCENDING);
745
746         /* set up signals */
747         g_signal_connect (selection, "changed",
748                           G_CALLBACK (log_window_chats_changed_cb),
749                           window);
750
751         g_object_unref (store);
752 }
753
754 static void
755 log_window_chats_accounts_changed_cb (GtkWidget       *combobox,
756                                       EmpathyLogWindow *window)
757 {
758         /* Clear all current messages shown in the textview */
759         empathy_chat_view_clear (window->chatview_chats);
760
761         log_window_chats_populate (window);
762 }
763
764 static void
765 log_window_chats_set_selected  (EmpathyLogWindow *window,
766                                 TpAccount        *account,
767                                 const gchar     *chat_id,
768                                 gboolean         is_chatroom)
769 {
770         EmpathyAccountChooser *account_chooser;
771         GtkTreeView          *view;
772         GtkTreeModel         *model;
773         GtkTreeSelection     *selection;
774         GtkTreeIter           iter;
775         GtkTreePath          *path;
776         gboolean              ok;
777
778         account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats);
779         empathy_account_chooser_set_account (account_chooser, account);
780
781         view = GTK_TREE_VIEW (window->treeview_chats);
782         model = gtk_tree_view_get_model (view);
783         selection = gtk_tree_view_get_selection (view);
784
785         if (!gtk_tree_model_get_iter_first (model, &iter)) {
786                 return;
787         }
788
789         for (ok = TRUE; ok; ok = gtk_tree_model_iter_next (model, &iter)) {
790                 TpAccount *this_account;
791                 gchar     *this_chat_id;
792                 gboolean   this_is_chatroom;
793
794                 gtk_tree_model_get (model, &iter,
795                                     COL_CHAT_ACCOUNT, &this_account,
796                                     COL_CHAT_ID, &this_chat_id,
797                                     COL_CHAT_IS_CHATROOM, &this_is_chatroom,
798                                     -1);
799
800                 if (this_account == account &&
801                     strcmp (this_chat_id, chat_id) == 0 &&
802                     this_is_chatroom == is_chatroom) {
803                         gtk_tree_selection_select_iter (selection, &iter);
804                         path = gtk_tree_model_get_path (model, &iter);
805                         gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
806                         gtk_tree_path_free (path);
807                         g_object_unref (this_account);
808                         g_free (this_chat_id);
809                         break;
810                 }
811
812                 g_object_unref (this_account);
813                 g_free (this_chat_id);
814         }
815 }
816
817 static gboolean
818 log_window_chats_get_selected (EmpathyLogWindow  *window,
819                                TpAccount       **account,
820                                gchar           **chat_id,
821                                gboolean         *is_chatroom)
822 {
823         GtkTreeView      *view;
824         GtkTreeModel     *model;
825         GtkTreeSelection *selection;
826         GtkTreeIter       iter;
827         gchar            *id = NULL;
828         TpAccount        *acc = NULL;
829         gboolean          room = FALSE;
830
831         view = GTK_TREE_VIEW (window->treeview_chats);
832         model = gtk_tree_view_get_model (view);
833         selection = gtk_tree_view_get_selection (view);
834
835         if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
836                 return FALSE;
837         }
838
839         gtk_tree_model_get (model, &iter,
840                             COL_CHAT_ACCOUNT, &acc,
841                             COL_CHAT_ID, &id,
842                             COL_CHAT_IS_CHATROOM, &room,
843                             -1);
844
845         if (chat_id) {
846                 *chat_id = id;
847         } else {
848                 g_free (id);
849         }
850         if (account) {
851                 *account = acc;
852         } else {
853                 g_object_unref (acc);
854         }
855         if (is_chatroom) {
856                 *is_chatroom = room;
857         }
858
859         return TRUE;
860 }
861
862 static void
863 log_window_chats_get_messages (EmpathyLogWindow *window,
864                                const gchar     *date_to_show)
865 {
866         TpAccount     *account;
867         gchar         *chat_id;
868         gboolean       is_chatroom;
869         EmpathyMessage *message;
870         GList         *messages;
871         GList         *dates = NULL;
872         GList         *l;
873         const gchar   *date;
874         guint          year_selected;
875         guint          year;
876         guint          month;
877         guint          month_selected;
878         guint          day;
879
880         if (!log_window_chats_get_selected (window, &account,
881                                             &chat_id, &is_chatroom)) {
882                 return;
883         }
884
885         g_signal_handlers_block_by_func (window->calendar_chats,
886                                          log_window_calendar_chats_day_selected_cb,
887                                          window);
888
889         /* Either use the supplied date or get the last */
890         date = date_to_show;
891         if (!date) {
892                 gboolean day_selected = FALSE;
893
894                 /* Get a list of dates and show them on the calendar */
895                 dates = empathy_log_manager_get_dates (window->log_manager,
896                                                        account, chat_id,
897                                                        is_chatroom);
898
899                 for (l = dates; l; l = l->next) {
900                         const gchar *str;
901
902                         str = l->data;
903                         if (!str) {
904                                 continue;
905                         }
906
907                         sscanf (str, "%4d%2d%2d", &year, &month, &day);
908                         gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
909                                                &year_selected,
910                                                &month_selected,
911                                                NULL);
912
913                         month_selected++;
914
915                         if (!l->next) {
916                                 date = str;
917                         }
918
919                         if (year != year_selected || month != month_selected) {
920                                 continue;
921                         }
922
923
924                         DEBUG ("Marking date:'%s'", str);
925                         gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day);
926
927                         if (l->next) {
928                                 continue;
929                         }
930
931                         day_selected = TRUE;
932
933                         gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day);
934                 }
935
936                 if (!day_selected) {
937                         /* Unselect the day in the calendar */
938                         gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), 0);
939                 }
940         } else {
941                 sscanf (date, "%4d%2d%2d", &year, &month, &day);
942                 gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
943                                        &year_selected,
944                                        &month_selected,
945                                        NULL);
946
947                 month_selected++;
948
949                 if (year != year_selected && month != month_selected) {
950                         day = 0;
951                 }
952
953                 gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day);
954         }
955
956         g_signal_handlers_unblock_by_func (window->calendar_chats,
957                                            log_window_calendar_chats_day_selected_cb,
958                                            window);
959
960         if (!date) {
961                 goto OUT;
962         }
963
964         /* Clear all current messages shown in the textview */
965         empathy_chat_view_clear (window->chatview_chats);
966
967         /* Turn off scrolling temporarily */
968         empathy_chat_view_scroll (window->chatview_find, FALSE);
969
970         /* Get messages */
971         messages = empathy_log_manager_get_messages_for_date (window->log_manager,
972                                                               account, chat_id,
973                                                               is_chatroom,
974                                                               date);
975
976         for (l = messages; l; l = l->next) {
977                 message = l->data;
978
979                 empathy_chat_view_append_message (window->chatview_chats,
980                                                  message);
981                 g_object_unref (message);
982         }
983         g_list_free (messages);
984
985         /* Turn back on scrolling */
986         empathy_chat_view_scroll (window->chatview_find, TRUE);
987
988         /* Give the search entry main focus */
989         gtk_widget_grab_focus (window->entry_chats);
990
991 OUT:
992         g_list_foreach (dates, (GFunc) g_free, NULL);
993         g_list_free (dates);
994         g_object_unref (account);
995         g_free (chat_id);
996 }
997
998 static void
999 log_window_calendar_chats_day_selected_cb (GtkWidget       *calendar,
1000                                            EmpathyLogWindow *window)
1001 {
1002         guint  year;
1003         guint  month;
1004         guint  day;
1005
1006         gchar *date;
1007
1008         gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day);
1009
1010         /* We need this hear because it appears that the months start from 0 */
1011         month++;
1012
1013         date = g_strdup_printf ("%4.4d%2.2d%2.2d", year, month, day);
1014
1015         DEBUG ("Currently selected date is:'%s'", date);
1016
1017         log_window_chats_get_messages (window, date);
1018
1019         g_free (date);
1020 }
1021
1022 static void
1023 log_window_calendar_chats_month_changed_cb (GtkWidget       *calendar,
1024                                             EmpathyLogWindow *window)
1025 {
1026         TpAccount     *account;
1027         gchar         *chat_id;
1028         gboolean       is_chatroom;
1029         guint          year_selected;
1030         guint          month_selected;
1031
1032         GList         *dates;
1033         GList         *l;
1034
1035         gtk_calendar_clear_marks (GTK_CALENDAR (calendar));
1036
1037         if (!log_window_chats_get_selected (window, &account,
1038                                             &chat_id, &is_chatroom)) {
1039                 DEBUG ("No chat selected to get dates for...");
1040                 return;
1041         }
1042
1043         g_object_get (calendar,
1044                       "month", &month_selected,
1045                       "year", &year_selected,
1046                       NULL);
1047
1048         /* We need this hear because it appears that the months start from 0 */
1049         month_selected++;
1050
1051         /* Get the log object for this contact */
1052         dates = empathy_log_manager_get_dates (window->log_manager, account,
1053                                                chat_id, is_chatroom);
1054         g_object_unref (account);
1055         g_free (chat_id);
1056
1057         for (l = dates; l; l = l->next) {
1058                 const gchar *str;
1059                 guint        year;
1060                 guint        month;
1061                 guint        day;
1062
1063                 str = l->data;
1064                 if (!str) {
1065                         continue;
1066                 }
1067
1068                 sscanf (str, "%4d%2d%2d", &year, &month, &day);
1069
1070                 if (year == year_selected && month == month_selected) {
1071                         DEBUG ("Marking date:'%s'", str);
1072                         gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day);
1073                 }
1074         }
1075
1076         g_list_foreach (dates, (GFunc) g_free, NULL);
1077         g_list_free (dates);
1078
1079         DEBUG ("Currently showing month %d and year %d", month_selected,
1080                 year_selected);
1081 }
1082
1083 static void
1084 log_window_entry_chats_changed_cb (GtkWidget       *entry,
1085                                    EmpathyLogWindow *window)
1086 {
1087         const gchar *str;
1088
1089         str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
1090         empathy_chat_view_highlight (window->chatview_chats, str);
1091
1092         if (str) {
1093                 empathy_chat_view_find_next (window->chatview_chats,
1094                                             str,
1095                                             TRUE);
1096         }
1097 }
1098
1099 static void
1100 log_window_entry_chats_activate_cb (GtkWidget       *entry,
1101                                     EmpathyLogWindow *window)
1102 {
1103         const gchar *str;
1104
1105         str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
1106
1107         if (str) {
1108                 empathy_chat_view_find_next (window->chatview_chats,
1109                                             str,
1110                                             FALSE);
1111         }
1112 }
1113