b4a8a0a81fd2f87909d46728e725ac869b78f980
[modest] / src / gtk / modest-ui-main-view.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30
31 #include <gtk/gtk.h>
32 #include <glade/glade.h>
33 #include <glib/gi18n.h>
34 #include <string.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif /*HAVE_CONFIG_H*/
39
40 /* TODO: put in auto* */
41 #include <tny-text-buffer-stream.h>
42 #include <tny-list.h>
43 #include <tny-msg-folder.h>
44
45 #include "../modest-ui.h"
46 #include "../modest-window-mgr.h"
47 #include "../modest-account-mgr.h"
48 #include "../modest-account-mgr.h"
49 #include "../modest-identity-mgr.h"
50
51 #include "../modest-tny-account-store.h"
52 #include "../modest-tny-folder-tree-view.h"
53 #include "../modest-tny-header-tree-view.h"
54 #include "../modest-tny-msg-view.h"
55 #include "../modest-tny-transport-actions.h"
56 #include "../modest-tny-store-actions.h"
57
58 #include "../modest-text-utils.h"
59 #include "../modest-tny-msg-actions.h"
60
61 #include "../modest-editor-window.h"
62
63 #include "modest-ui-glade.h"
64 #include "modest-ui-wizard.h"
65 #include "modest-ui-account-setup.h"
66
67 #include "modest-ui-main-view.h"
68 #include "modest-ui-message-editor.h"
69 #include "modest-ui-message-viewer.h"
70
71
72 static GtkWidget* modest_main_window_folder_tree (ModestAccountMgr *modest_acc_mgr,
73                                                   TnyAccountStoreIface *account_store);
74
75 static GtkWidget* modest_main_window_header_tree (TnyMsgFolderIface *folder);
76
77 static void on_folder_clicked (ModestTnyFolderTreeView *folder_tree,
78                                TnyMsgFolderIface *folder,
79                                gpointer data);
80
81 static void on_message_clicked (ModestTnyFolderTreeView *folder_tree,
82                                 TnyMsgIface *message,
83                                 gpointer data);
84
85 static void on_reply_clicked (GtkWidget *widget, gpointer user_data);
86
87 static void on_forward_clicked (GtkWidget *widget, gpointer user_data);
88
89 static void on_delete_clicked (GtkWidget *widget, gpointer user_data);
90
91 static void on_sendreceive_button_clicked (GtkWidget *widget, gpointer user_data);
92
93 static void on_forward_attached_activated (GtkWidget *widget, gpointer user_data);
94
95 static void on_headers_status_update (GtkWidget *header_view, const gchar *msg, gint status,
96                           gpointer user_data);
97 static void on_status_cleanup (gpointer user_data);
98
99 static void register_toolbar_callbacks (ModestUI *modest_ui);
100
101
102 static void
103 modest_ui_main_view_destroy (GtkWidget *win, GdkEvent *event, gpointer data)
104 {
105         ModestUIPrivate *priv;
106
107         g_return_if_fail (data);
108         g_return_if_fail(MODEST_IS_UI(data));
109         priv = MODEST_UI_GET_PRIVATE((ModestUI *)data);
110         g_return_if_fail(priv);
111         if (!modest_window_mgr_unregister (priv->modest_window_mgr, G_OBJECT(win)))
112                 g_warning ("modest window mgr: failed to unregister %p",
113                            G_OBJECT(win));
114         else
115                 gtk_widget_hide(win);
116 }
117 gboolean
118 modest_ui_show_main_window (ModestUI *modest_ui)
119 {
120         GtkWidget       *win;
121         gint              height, width;
122         ModestUIPrivate *priv;
123         GtkWidget     *folder_view, *header_view;
124         GtkWidget     *message_view;
125         GtkWidget     *account_settings_item;
126         GtkWidget     *delete_item;
127         GtkWidget     *open_item;
128         GtkWidget     *forward_attached_menu_item;
129         GtkWidget     *view_attachments_item;
130         GtkWidget     *new_account_item;
131         
132         GtkWidget  *folder_view_holder,
133                 *header_view_holder,
134                 *mail_paned;
135
136         priv = MODEST_UI_GET_PRIVATE(modest_ui);
137         
138         height = modest_conf_get_int (priv->modest_conf,
139                                       MODEST_MAIN_WINDOW_HEIGHT,NULL);
140         width  = modest_conf_get_int (priv->modest_conf,
141                                       MODEST_MAIN_WINDOW_WIDTH,NULL);
142
143         win = glade_xml_get_widget (priv->glade_xml, "main");
144         if (!win) {
145                 g_warning ("could not create main window");
146                 return FALSE;
147         }
148
149         folder_view = GTK_WIDGET(modest_main_window_folder_tree(priv->modest_acc_mgr,
150                                                                 priv->account_store));
151         priv->folder_view = folder_view;
152         folder_view_holder = glade_xml_get_widget (priv->glade_xml, "folders");
153         if (!folder_view||!folder_view_holder) {
154                 g_warning ("failed to create folder tree");
155                 return FALSE;
156         }
157         gtk_container_add (GTK_CONTAINER(folder_view_holder), folder_view);
158         
159         header_view  =  GTK_WIDGET(modest_main_window_header_tree (NULL));
160         priv->header_view = header_view;
161         header_view_holder = glade_xml_get_widget (priv->glade_xml, "mail_list");
162         if (!header_view) {
163                 g_warning ("failed to create header tree");
164                 return FALSE;
165         }
166         gtk_container_add (GTK_CONTAINER(header_view_holder), header_view);
167
168         g_signal_connect (G_OBJECT(folder_view), "folder_selected",
169                           G_CALLBACK(on_folder_clicked), modest_ui);
170         
171         message_view  = GTK_WIDGET(modest_tny_msg_view_new (NULL));
172         priv->message_view = message_view;
173         if (!message_view) {
174                 g_warning ("failed to create message view");
175                 return FALSE;
176         }
177         //g_signal_connect(G_OBJECT(message_view), "on_mailto_clicked",
178         //            G_CALLBACK(ui_on_mailto_clicked), modest_ui);
179
180         mail_paned = glade_xml_get_widget (priv->glade_xml, "mail_paned");
181         gtk_paned_add2 (GTK_PANED(mail_paned), message_view);
182
183         g_signal_connect (header_view, "message_selected",
184                           G_CALLBACK(on_message_clicked),
185                           modest_ui);
186
187         g_signal_connect (header_view, "status_update",
188                           G_CALLBACK(on_headers_status_update), modest_ui);
189
190         g_signal_connect (header_view, "row-activated",
191                           G_CALLBACK(on_message_activated),
192                           modest_ui);
193
194         account_settings_item = glade_xml_get_widget (priv->glade_xml, "AccountSettingsMenuItem");
195         if (!account_settings_item) {
196                 g_warning ("The account settings item isn't available!\n");
197                 return FALSE;
198         }
199
200         g_signal_connect (account_settings_item, "activate",
201                           G_CALLBACK(account_settings), modest_ui);
202
203         new_account_item = glade_xml_get_widget (priv->glade_xml, "NewAccountWizardMenuItem");
204         if (!new_account_item) {
205                 g_warning ("The new account item isn't available!\n");
206                 return FALSE;
207         }
208
209         g_signal_connect (new_account_item, "activate",
210                 G_CALLBACK(new_wizard_account), modest_ui);
211
212         open_item = glade_xml_get_widget (priv->glade_xml, "open1");
213         if (!open_item) {
214                 g_warning ("The open item isn't available!\n");
215                 return FALSE;
216         }
217         g_signal_connect (open_item, "activate", G_CALLBACK(on_open_message_clicked),
218                           modest_ui);
219
220         delete_item = glade_xml_get_widget (priv->glade_xml, "delete1");
221         if (!delete_item) {
222                 g_warning ("The delete item isn't available!\n");
223                 return FALSE;
224         }
225         g_signal_connect (delete_item, "activate", G_CALLBACK(on_delete_clicked),
226                           modest_ui);
227
228         view_attachments_item = glade_xml_get_widget (priv->glade_xml, "menu_view_attachments");
229         if (!view_attachments_item) {
230                 g_warning ("The view_attachments_item isn't available!");
231                 return FALSE;
232         }
233
234         forward_attached_menu_item = glade_xml_get_widget (priv->glade_xml, "forward_attached");
235         if (!forward_attached_menu_item) {
236                 g_warning ("The forward_attached_menu_item isn't available!");
237                 return FALSE;
238         }
239         g_signal_connect (forward_attached_menu_item, "activate", G_CALLBACK(on_forward_attached_activated),
240                           modest_ui);
241
242         register_toolbar_callbacks (modest_ui);
243
244         modest_window_mgr_register (priv->modest_window_mgr,
245                                     G_OBJECT(win), MODEST_MAIN_WINDOW, 0);
246         g_signal_connect (win, "destroy-event", G_CALLBACK(modest_ui_main_view_destroy),
247                           modest_ui);
248         g_signal_connect (win, "delete-event", G_CALLBACK(modest_ui_main_view_destroy),
249                           modest_ui);
250         gtk_widget_set_usize (GTK_WIDGET(win), width, height);
251         gtk_window_set_title (GTK_WINDOW(win), PACKAGE_STRING);
252
253         gtk_widget_show_all (win);
254         return TRUE;
255 }
256
257
258 static void
259 register_toolbar_callbacks (ModestUI *modest_ui)
260 {
261         ModestUIPrivate *priv;
262         GtkWidget *button;
263
264         g_return_if_fail (modest_ui);
265
266         priv = MODEST_UI_GET_PRIVATE (modest_ui);
267
268         button = glade_xml_get_widget (priv->glade_xml, "toolb_new_mail");
269         if (button)
270                 g_signal_connect (button, "clicked",
271                                   G_CALLBACK(on_new_mail_clicked), modest_ui);
272
273         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply");
274         if (button) {
275                 g_signal_connect (button, "clicked",
276                                   G_CALLBACK(on_reply_clicked), modest_ui);
277                 gtk_widget_set_sensitive(button, FALSE);
278         }
279
280         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply_all");
281         if (button) {
282                 //g_signal_connect (button, "clicked",
283                 //                G_CALLBACK(on_reply_all_clicked), modest_ui);
284                 gtk_widget_set_sensitive(button, FALSE);
285         }
286
287         button = glade_xml_get_widget (priv->glade_xml, "toolb_forward");
288         if (button) {
289                 g_signal_connect (button, "clicked",
290                                   G_CALLBACK(on_forward_clicked), modest_ui);
291                 gtk_widget_set_sensitive(button, FALSE);
292         }
293
294         button = glade_xml_get_widget (priv->glade_xml, "toolb_move_to");
295         if (button) {
296                 //g_signal_connect (button, "clicked",
297                 //                G_CALLBACK(on_move_to_clicked), modest_ui);
298                 gtk_widget_set_sensitive(button, FALSE);
299         }
300
301         button = glade_xml_get_widget (priv->glade_xml, "toolb_delete");
302         if (button) {
303                 g_signal_connect (button, "clicked",
304                                   G_CALLBACK(on_delete_clicked), modest_ui);
305                 gtk_widget_set_sensitive(button, FALSE);
306         }
307
308         button = glade_xml_get_widget (priv->glade_xml, "toolb_send_receive");
309         if (button) {
310                 g_signal_connect (button, "clicked",
311                                   G_CALLBACK(on_sendreceive_button_clicked), modest_ui);
312                 gtk_widget_set_sensitive(button, TRUE);
313         }
314 }
315
316
317 static void
318 on_folder_clicked (ModestTnyFolderTreeView *folder_tree,
319                    TnyMsgFolderIface *folder,
320                    gpointer data)
321 {
322         GtkWidget *win;
323         GtkWidget *button;
324         ModestTnyHeaderTreeView *tree_view;
325         ModestTnyMsgView *msg_view;
326         ModestUIPrivate *priv;
327         GtkWidget *scrollview;
328
329         g_return_if_fail (folder);
330         g_return_if_fail (data);
331
332         priv = MODEST_UI_GET_PRIVATE(data);
333         scrollview = glade_xml_get_widget (priv->glade_xml,"mail_list");
334
335         tree_view = MODEST_TNY_HEADER_TREE_VIEW (priv->header_view);
336
337         win = glade_xml_get_widget (priv->glade_xml, "main");
338         gtk_window_set_title (GTK_WINDOW(win),
339                               tny_msg_folder_iface_get_name(folder));
340
341         modest_tny_header_tree_view_set_folder (tree_view, folder);
342         priv->current_folder = folder;
343
344         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply");
345         if (button) {
346                 gtk_widget_set_sensitive(button, FALSE);
347         }
348
349         button = glade_xml_get_widget (priv->glade_xml, "toolb_forward");
350         if (button) {
351                 gtk_widget_set_sensitive(button, FALSE);
352         }
353
354         button = glade_xml_get_widget (priv->glade_xml, "toolb_delete");
355         if (button) {
356                 gtk_widget_set_sensitive(button, FALSE);
357         }
358
359         msg_view = MODEST_TNY_MSG_VIEW (priv->message_view);
360         g_return_if_fail (msg_view);
361
362         modest_tny_msg_view_set_message  (msg_view, NULL);
363 }
364
365
366 static void
367 on_message_clicked (ModestTnyFolderTreeView *folder_tree,
368                                 TnyMsgIface *message,
369                                 gpointer data)
370 {
371         GtkWidget *button;
372         ModestTnyMsgView *msg_view;
373         ModestUIPrivate *priv;
374
375         g_return_if_fail (data);
376
377         priv = MODEST_UI_GET_PRIVATE (data);
378         msg_view = MODEST_TNY_MSG_VIEW (priv->message_view);
379
380         modest_tny_msg_view_set_message (msg_view, message);
381         
382         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply");
383         if (button) {
384                 gtk_widget_set_sensitive(button, TRUE);
385         }
386         button = glade_xml_get_widget (priv->glade_xml, "toolb_forward");
387         if (button) {
388                 gtk_widget_set_sensitive(button, TRUE);
389         }
390         button = glade_xml_get_widget (priv->glade_xml, "toolb_delete");
391         if (button) {
392                 gtk_widget_set_sensitive(button, TRUE);
393         }
394 }
395
396
397 static GtkWidget*
398 modest_main_window_header_tree (TnyMsgFolderIface *folder)
399 {
400         int i;
401         GSList *columns = NULL;
402         GtkWidget *header_tree;
403         ModestTnyHeaderTreeViewColumn cols[] = {
404                 MODEST_TNY_HEADER_TREE_VIEW_COLUMN_MSGTYPE,
405                 MODEST_TNY_HEADER_TREE_VIEW_COLUMN_ATTACH,
406                 MODEST_TNY_HEADER_TREE_VIEW_COLUMN_FROM,
407                 MODEST_TNY_HEADER_TREE_VIEW_COLUMN_SUBJECT,
408                 MODEST_TNY_HEADER_TREE_VIEW_COLUMN_RECEIVED_DATE
409         };
410
411         for (i = 0 ; i != sizeof(cols) / sizeof(ModestTnyHeaderTreeViewColumn); ++i)
412                 columns = g_slist_append (columns, GINT_TO_POINTER(cols[i]));
413
414         header_tree = GTK_WIDGET(modest_tny_header_tree_view_new(folder, columns,
415                                                                  MODEST_TNY_HEADER_TREE_VIEW_STYLE_NORMAL));
416         g_slist_free (columns);
417
418         if (!header_tree) {
419                 g_warning ("could not create header tree");
420                 return NULL;
421         }
422
423         return GTK_WIDGET(header_tree);
424 }
425
426
427 static GtkWidget*
428 modest_main_window_folder_tree (ModestAccountMgr *modest_acc_mgr,
429                                 TnyAccountStoreIface *account_store)
430 {
431         GtkWidget *folder_tree;
432
433         folder_tree = GTK_WIDGET (modest_tny_folder_tree_view_new (account_store));
434         if (!folder_tree) {
435                 g_warning ("could not create folder list");
436                 return NULL;
437         }
438
439         return folder_tree;
440 }
441
442
443 static void
444 on_reply_clicked (GtkWidget *widget, gpointer user_data)
445 {
446         ModestUI *modest_ui = (ModestUI *)user_data;
447
448         quoted_send_msg (modest_ui, QUOTED_SEND_REPLY);
449 }
450
451
452 static void
453 on_forward_clicked (GtkWidget *widget, gpointer user_data)
454 {
455         ModestUI *modest_ui = (ModestUI *)user_data;
456
457         quoted_send_msg (modest_ui, QUOTED_SEND_FORWARD);
458 }
459
460
461 static void
462 on_delete_clicked (GtkWidget *widget, gpointer user_data)
463 {
464         ModestUI *modest_ui = (ModestUI *)user_data;
465         GtkTreeSelection *sel;
466         GtkTreeModel *model;
467         GtkTreeIter iter;
468         GtkTreeModel *mymodel;
469
470         ModestTnyHeaderTreeView *header_view;
471         ModestTnyMsgView *msg_view;
472         ModestUIPrivate *priv;
473
474         g_return_if_fail (modest_ui);
475
476         priv = MODEST_UI_GET_PRIVATE(modest_ui);
477
478         msg_view = MODEST_TNY_MSG_VIEW(priv->message_view);
479         g_return_if_fail (msg_view);
480
481         header_view = MODEST_TNY_HEADER_TREE_VIEW(priv->header_view);
482         g_return_if_fail (header_view);
483
484         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
485         g_return_if_fail (sel);
486
487         /* get all selected mails */
488         if (G_LIKELY (gtk_tree_selection_get_selected (sel, &model, &iter))) {
489                 TnyMsgHeaderIface *header;
490
491                 gtk_tree_model_get (model, &iter, TNY_MSG_HEADER_LIST_MODEL_INSTANCE_COLUMN,
492                         &header, -1);
493
494                 if (G_LIKELY (header)) {
495                         TnyMsgFolderIface *folder;
496                         // const TnyMsgIface *msg;
497
498                         if (GTK_IS_TREE_MODEL_SORT (model)) {
499                                 mymodel = gtk_tree_model_sort_get_model
500                                         (GTK_TREE_MODEL_SORT (model));
501                         } else
502                                 mymodel = model;
503
504                         folder = (TnyMsgFolderIface*)tny_msg_header_iface_get_folder (header);
505
506                         /* this will make the message as deleted */
507                         /*      tny_msg_folder_iface_expunge (folder); will finally delete messages */
508                         if (TNY_IS_MSG_FOLDER (folder))
509                                 tny_msg_folder_iface_remove_message (folder, header);
510                         gtk_widget_queue_draw (GTK_WIDGET (header_view));
511                 }
512         }
513 }
514
515
516 static void
517 on_sendreceive_button_clicked (GtkWidget *widget, gpointer user_data)
518 {
519         ModestUI *modest_ui;
520         ModestUIPrivate *priv;
521
522         TnyListIface *store_accounts;
523         TnyIteratorIface *iter;
524         
525         g_return_if_fail (user_data);
526
527         modest_ui = MODEST_UI(user_data);
528         priv = MODEST_UI_GET_PRIVATE(modest_ui);
529
530         store_accounts = tny_list_new (); 
531         tny_account_store_iface_get_accounts (priv->account_store, store_accounts,
532                                               TNY_ACCOUNT_STORE_IFACE_STORE_ACCOUNTS);
533         iter = tny_list_iface_create_iterator (store_accounts);
534         
535         if (tny_iterator_iface_has_first (iter)) {
536                 while (1) {
537                         TnyStoreAccountIface *account;
538                         account = TNY_STORE_ACCOUNT_IFACE(tny_iterator_iface_current(iter));
539                         modest_tny_store_actions_update_folders (account);
540                         
541                         if (!tny_iterator_iface_has_next (iter))
542                                 break;
543                         
544                         tny_iterator_iface_next (iter); 
545                 }
546                 
547         }
548         g_object_unref (G_OBJECT(iter));
549         g_object_unref (G_OBJECT(store_accounts));
550                 
551         if (priv->header_view && priv->current_folder) {
552                 
553                 modest_tny_header_tree_view_set_folder (MODEST_TNY_HEADER_TREE_VIEW(priv->header_view),
554                                                         priv->current_folder);
555                 gtk_widget_queue_draw (priv->header_view);
556         }
557 }
558
559
560 static void
561 on_forward_attached_activated (GtkWidget *widget, gpointer user_data)
562 {
563         ModestUI *modest_ui = (ModestUI *)user_data;
564
565         quoted_send_msg (modest_ui, QUOTED_SEND_FORWARD_ATTACHED);
566 }
567
568 static void
569 on_headers_status_update (GtkWidget *header_view, const gchar *msg, gint status_id,
570                           gpointer user_data)
571 {
572         ModestUIPrivate *priv;
573         ModestUI *modest_ui;
574
575         GtkStatusbar *status_bar;
576         GtkProgressBar *progress_bar;
577         GtkWidget    *status_box;
578         
579         modest_ui = MODEST_UI (user_data);
580         priv      = MODEST_UI_GET_PRIVATE(modest_ui);
581
582         progress_bar = GTK_PROGRESS_BAR(glade_xml_get_widget
583                                         (priv->glade_xml, "progressbar"));
584         status_bar   = GTK_STATUSBAR  (glade_xml_get_widget
585                                        (priv->glade_xml, "statusbar"));
586
587         
588         status_box   = glade_xml_get_widget (priv->glade_xml, "statusbox");
589         
590         
591         if (!status_bar || !progress_bar) {
592                 g_warning ("failed to find status / progress bar");
593                 return;
594         }
595
596         if (msg && status_id) {
597                 gtk_widget_show (status_box);
598                 gtk_progress_bar_pulse (progress_bar);
599                 gtk_statusbar_push (status_bar, status_id, msg);
600         } else {
601                 gtk_widget_hide   (status_box);
602                 gtk_statusbar_pop (status_bar, status_id);
603         }
604 }               
605