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