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