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