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