]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-log-window.c
Make use of tp-glib debug system.
[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., 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-utils.h>
39 #include <libempathy/empathy-time.h>
40
41 #include "empathy-log-window.h"
42 #include "empathy-account-chooser.h"
43 #include "empathy-chat-view.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         GladeXML               *glade;
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_new ();
163
164         filename = empathy_file_lookup ("empathy-log-window.glade",
165                                         "libempathy-gtk");
166         glade = empathy_glade_get_file (filename,
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         g_free (filename);
184
185         empathy_glade_connect (glade,
186                               window,
187                               "log_window", "destroy", log_window_destroy_cb,
188                               "entry_find", "changed", log_window_entry_find_changed_cb,
189                               "button_previous", "clicked", log_window_button_previous_clicked_cb,
190                               "button_next", "clicked", log_window_button_next_clicked_cb,
191                               "button_find", "clicked", log_window_button_find_clicked_cb,
192                               "entry_chats", "changed", log_window_entry_chats_changed_cb,
193                               "entry_chats", "activate", log_window_entry_chats_activate_cb,
194                               NULL);
195
196         g_object_unref (glade);
197
198         g_object_add_weak_pointer (G_OBJECT (window->window),
199                                    (gpointer) &window);
200
201         /* We set this up here so we can block it when needed. */
202         g_signal_connect (window->calendar_chats, "day-selected",
203                           G_CALLBACK (log_window_calendar_chats_day_selected_cb),
204                           window);
205         g_signal_connect (window->calendar_chats, "month-changed",
206                           G_CALLBACK (log_window_calendar_chats_month_changed_cb),
207                           window);
208
209         /* Configure Search EmpathyChatView */
210         window->chatview_find = empathy_chat_view_new ();
211         gtk_container_add (GTK_CONTAINER (window->scrolledwindow_find),
212                            GTK_WIDGET (window->chatview_find));
213         gtk_widget_show (GTK_WIDGET (window->chatview_find));
214
215         /* Configure Contacts EmpathyChatView */
216         window->chatview_chats = empathy_chat_view_new ();
217         gtk_container_add (GTK_CONTAINER (window->scrolledwindow_chats),
218                            GTK_WIDGET (window->chatview_chats));
219         gtk_widget_show (GTK_WIDGET (window->chatview_chats));
220
221         /* Account chooser for chats */
222         window->account_chooser_chats = empathy_account_chooser_new ();
223         account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats);
224
225         gtk_box_pack_start (GTK_BOX (window->vbox_chats),
226                             window->account_chooser_chats,
227                             FALSE, TRUE, 0);
228
229         g_signal_connect (window->account_chooser_chats, "changed",
230                           G_CALLBACK (log_window_chats_accounts_changed_cb),
231                           window);
232
233         /* Populate */
234         accounts = mc_accounts_list ();
235         account_num = g_list_length (accounts);
236         mc_accounts_list_free (accounts);
237
238         if (account_num > 1) {
239                 gtk_widget_show (window->vbox_chats);
240                 gtk_widget_show (window->account_chooser_chats);
241         } else {
242                 gtk_widget_hide (window->vbox_chats);
243                 gtk_widget_hide (window->account_chooser_chats);
244         }
245
246         /* Search List */
247         log_window_find_setup (window);
248
249         /* Contacts */
250         log_window_chats_setup (window);
251         log_window_chats_populate (window);
252
253         /* Select chat */
254         if (account && chat_id) {
255                 gtk_notebook_set_current_page (GTK_NOTEBOOK (window->notebook), 1);
256                 log_window_chats_set_selected (window, account,
257                                                chat_id, is_chatroom);
258         }
259
260         if (parent) {
261                 gtk_window_set_transient_for (GTK_WINDOW (window->window),
262                                               GTK_WINDOW (parent));
263         }
264
265         gtk_widget_show (window->window);
266
267         return window->window;
268 }
269
270 static void
271 log_window_destroy_cb (GtkWidget       *widget,
272                        EmpathyLogWindow *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_set_selected  (EmpathyLogWindow *window,
740                                 McAccount       *account,
741                                 const gchar     *chat_id,
742                                 gboolean         is_chatroom)
743 {
744         EmpathyAccountChooser *account_chooser;
745         GtkTreeView          *view;
746         GtkTreeModel         *model;
747         GtkTreeSelection     *selection;
748         GtkTreeIter           iter;
749         GtkTreePath          *path;
750         gboolean              ok;
751
752         account_chooser = EMPATHY_ACCOUNT_CHOOSER (window->account_chooser_chats);
753         empathy_account_chooser_set_account (account_chooser, account);
754
755         view = GTK_TREE_VIEW (window->treeview_chats);
756         model = gtk_tree_view_get_model (view);
757         selection = gtk_tree_view_get_selection (view);
758
759         if (!gtk_tree_model_get_iter_first (model, &iter)) {
760                 return;
761         }
762
763         for (ok = TRUE; ok; ok = gtk_tree_model_iter_next (model, &iter)) {
764                 McAccount *this_account;
765                 gchar     *this_chat_id;
766                 gboolean   this_is_chatroom;
767
768                 gtk_tree_model_get (model, &iter,
769                                     COL_CHAT_ACCOUNT, &this_account,
770                                     COL_CHAT_ID, &this_chat_id,
771                                     COL_CHAT_IS_CHATROOM, &this_is_chatroom,
772                                     -1);
773
774                 if (empathy_account_equal (this_account, account) &&
775                     strcmp (this_chat_id, chat_id) == 0 &&
776                     this_is_chatroom == is_chatroom) {
777                         gtk_tree_selection_select_iter (selection, &iter);
778                         path = gtk_tree_model_get_path (model, &iter);
779                         gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 0.5, 0.0);
780                         gtk_tree_path_free (path);
781                         g_object_unref (this_account);
782                         g_free (this_chat_id);
783                         break;
784                 }
785
786                 g_object_unref (this_account);
787                 g_free (this_chat_id);
788         }
789 }
790
791 static gboolean
792 log_window_chats_get_selected (EmpathyLogWindow  *window,
793                                McAccount       **account,
794                                gchar           **chat_id,
795                                gboolean         *is_chatroom)
796 {
797         GtkTreeView      *view;
798         GtkTreeModel     *model;
799         GtkTreeSelection *selection;
800         GtkTreeIter       iter;
801         gchar            *id = NULL;
802         McAccount        *acc = NULL;
803         gboolean          room = FALSE;
804
805         view = GTK_TREE_VIEW (window->treeview_chats);
806         model = gtk_tree_view_get_model (view);
807         selection = gtk_tree_view_get_selection (view);
808
809         if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
810                 return FALSE;
811         }
812
813         gtk_tree_model_get (model, &iter,
814                             COL_CHAT_ACCOUNT, &acc,
815                             COL_CHAT_ID, &id,
816                             COL_CHAT_IS_CHATROOM, &room,
817                             -1);
818
819         if (chat_id) {
820                 *chat_id = id;
821         } else {
822                 g_free (id);
823         }
824         if (account) {
825                 *account = acc;
826         } else {
827                 g_object_unref (acc);
828         }
829         if (is_chatroom) {
830                 *is_chatroom = room;
831         }
832
833         return TRUE;
834 }
835
836 static void
837 log_window_chats_get_messages (EmpathyLogWindow *window,
838                                const gchar     *date_to_show)
839 {
840         McAccount     *account;
841         gchar         *chat_id;
842         gboolean       is_chatroom;
843         EmpathyMessage *message;
844         GList         *messages;
845         GList         *dates = NULL;
846         GList         *l;
847         const gchar   *date;
848         guint          year_selected;
849         guint          year;
850         guint          month;
851         guint          month_selected;
852         guint          day;
853
854         if (!log_window_chats_get_selected (window, &account,
855                                             &chat_id, &is_chatroom)) {
856                 return;
857         }
858
859         g_signal_handlers_block_by_func (window->calendar_chats,
860                                          log_window_calendar_chats_day_selected_cb,
861                                          window);
862
863         /* Either use the supplied date or get the last */
864         date = date_to_show;
865         if (!date) {
866                 gboolean day_selected = FALSE;
867
868                 /* Get a list of dates and show them on the calendar */
869                 dates = empathy_log_manager_get_dates (window->log_manager,
870                                                        account, chat_id,
871                                                        is_chatroom);
872
873                 for (l = dates; l; l = l->next) {
874                         const gchar *str;
875
876                         str = l->data;
877                         if (!str) {
878                                 continue;
879                         }
880
881                         sscanf (str, "%4d%2d%2d", &year, &month, &day);
882                         gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
883                                                &year_selected,
884                                                &month_selected,
885                                                NULL);
886
887                         month_selected++;
888
889                         if (!l->next) {
890                                 date = str;
891                         }
892
893                         if (year != year_selected || month != month_selected) {
894                                 continue;
895                         }
896
897
898                         DEBUG ("Marking date:'%s'", str);
899                         gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day);
900
901                         if (l->next) {
902                                 continue;
903                         }
904
905                         day_selected = TRUE;
906
907                         gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day);
908                 }
909
910                 if (!day_selected) {
911                         /* Unselect the day in the calendar */
912                         gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), 0);
913                 }
914         } else {
915                 sscanf (date, "%4d%2d%2d", &year, &month, &day);
916                 gtk_calendar_get_date (GTK_CALENDAR (window->calendar_chats),
917                                        &year_selected,
918                                        &month_selected,
919                                        NULL);
920
921                 month_selected++;
922
923                 if (year != year_selected && month != month_selected) {
924                         day = 0;
925                 }
926
927                 gtk_calendar_select_day (GTK_CALENDAR (window->calendar_chats), day);
928         }
929
930         g_signal_handlers_unblock_by_func (window->calendar_chats,
931                                            log_window_calendar_chats_day_selected_cb,
932                                            window);
933
934         if (!date) {
935                 goto OUT;
936         }
937
938         /* Clear all current messages shown in the textview */
939         empathy_chat_view_clear (window->chatview_chats);
940
941         /* Turn off scrolling temporarily */
942         empathy_chat_view_scroll (window->chatview_find, FALSE);
943
944         /* Get messages */
945         messages = empathy_log_manager_get_messages_for_date (window->log_manager,
946                                                               account, chat_id,
947                                                               is_chatroom,
948                                                               date);
949
950         for (l = messages; l; l = l->next) {
951                 message = l->data;
952
953                 empathy_chat_view_append_message (window->chatview_chats,
954                                                  message);
955                 g_object_unref (message);
956         }
957         g_list_free (messages);
958
959         /* Turn back on scrolling */
960         empathy_chat_view_scroll (window->chatview_find, TRUE);
961
962         /* Give the search entry main focus */
963         gtk_widget_grab_focus (window->entry_chats);
964
965 OUT:
966         g_list_foreach (dates, (GFunc) g_free, NULL);
967         g_list_free (dates);
968         g_object_unref (account);
969         g_free (chat_id);
970 }
971
972 static void
973 log_window_calendar_chats_day_selected_cb (GtkWidget       *calendar,
974                                            EmpathyLogWindow *window)
975 {
976         guint  year;
977         guint  month;
978         guint  day;
979
980         gchar *date;
981
982         gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day);
983
984         /* We need this hear because it appears that the months start from 0 */
985         month++;
986
987         date = g_strdup_printf ("%4.4d%2.2d%2.2d", year, month, day);
988
989         DEBUG ("Currently selected date is:'%s'", date);
990
991         log_window_chats_get_messages (window, date);
992
993         g_free (date);
994 }
995
996 static void
997 log_window_calendar_chats_month_changed_cb (GtkWidget       *calendar,
998                                             EmpathyLogWindow *window)
999 {
1000         McAccount     *account;
1001         gchar         *chat_id;
1002         gboolean       is_chatroom;
1003         guint          year_selected;
1004         guint          month_selected;
1005
1006         GList         *dates;
1007         GList         *l;
1008
1009         gtk_calendar_clear_marks (GTK_CALENDAR (calendar));
1010
1011         if (!log_window_chats_get_selected (window, &account,
1012                                             &chat_id, &is_chatroom)) {
1013                 DEBUG ("No chat selected to get dates for...");
1014                 return;
1015         }
1016
1017         g_object_get (calendar,
1018                       "month", &month_selected,
1019                       "year", &year_selected,
1020                       NULL);
1021
1022         /* We need this hear because it appears that the months start from 0 */
1023         month_selected++;
1024
1025         /* Get the log object for this contact */
1026         dates = empathy_log_manager_get_dates (window->log_manager, account,
1027                                                chat_id, is_chatroom);
1028         g_object_unref (account);
1029         g_free (chat_id);
1030
1031         for (l = dates; l; l = l->next) {
1032                 const gchar *str;
1033                 guint        year;
1034                 guint        month;
1035                 guint        day;
1036
1037                 str = l->data;
1038                 if (!str) {
1039                         continue;
1040                 }
1041
1042                 sscanf (str, "%4d%2d%2d", &year, &month, &day);
1043
1044                 if (year == year_selected && month == month_selected) {
1045                         DEBUG ("Marking date:'%s'", str);
1046                         gtk_calendar_mark_day (GTK_CALENDAR (window->calendar_chats), day);
1047                 }
1048         }
1049
1050         g_list_foreach (dates, (GFunc) g_free, NULL);
1051         g_list_free (dates);
1052
1053         DEBUG ("Currently showing month %d and year %d", month_selected,
1054                 year_selected);
1055 }
1056
1057 static void
1058 log_window_entry_chats_changed_cb (GtkWidget       *entry,
1059                                    EmpathyLogWindow *window)
1060 {
1061         const gchar *str;
1062
1063         str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
1064         empathy_chat_view_highlight (window->chatview_chats, str);
1065
1066         if (str) {
1067                 empathy_chat_view_find_next (window->chatview_chats,
1068                                             str,
1069                                             TRUE);
1070         }
1071 }
1072
1073 static void
1074 log_window_entry_chats_activate_cb (GtkWidget       *entry,
1075                                     EmpathyLogWindow *window)
1076 {
1077         const gchar *str;
1078
1079         str = gtk_entry_get_text (GTK_ENTRY (window->entry_chats));
1080
1081         if (str) {
1082                 empathy_chat_view_find_next (window->chatview_chats,
1083                                             str,
1084                                             FALSE);
1085         }
1086 }
1087