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