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