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