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