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