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