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