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