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