b6c21c78b963c136eb51f0ee8971d77baf34c8a3
[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 "../widgets/modest-folder-view.h"
53 #include "../widgets/modest-header-view.h"
54 #include "../widgets/modest-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 (ModestFolderView *folder_tree,
78                                TnyMsgFolderIface *folder,
79                                gpointer data);
80
81 static void on_message_clicked (ModestFolderView *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 register_toolbar_callbacks (ModestUI *modest_ui);
98
99
100 static void
101 modest_ui_main_view_destroy (GtkWidget *win, GdkEvent *event, gpointer data)
102 {
103         ModestUIPrivate *priv;
104
105         g_return_if_fail (data);
106         g_return_if_fail(MODEST_IS_UI(data));
107         priv = MODEST_UI_GET_PRIVATE((ModestUI *)data);
108         g_return_if_fail(priv);
109         if (!modest_window_mgr_unregister (priv->modest_window_mgr, G_OBJECT(win)))
110                 g_warning ("modest window mgr: failed to unregister %p",
111                            G_OBJECT(win));
112         else
113                 gtk_widget_hide(win);
114 }
115 gboolean
116 modest_ui_show_main_window (ModestUI *modest_ui)
117 {
118         GtkWidget       *win;
119         gint              height, width;
120         ModestUIPrivate *priv;
121         GtkWidget     *folder_view, *header_view;
122         GtkWidget     *message_view;
123         GtkWidget     *account_settings_item;
124         GtkWidget     *delete_item;
125         GtkWidget     *open_item;
126         GtkWidget     *forward_attached_menu_item;
127         GtkWidget     *view_attachments_item;
128         GtkWidget     *new_account_item;
129         
130         GtkWidget  *folder_view_holder,
131                 *header_view_holder,
132                 *mail_paned;
133
134         priv = MODEST_UI_GET_PRIVATE(modest_ui);
135         
136         height = modest_conf_get_int (priv->modest_conf,
137                                       MODEST_MAIN_WINDOW_HEIGHT,NULL);
138         width  = modest_conf_get_int (priv->modest_conf,
139                                       MODEST_MAIN_WINDOW_WIDTH,NULL);
140
141         win = glade_xml_get_widget (priv->glade_xml, "main");
142         if (!win) {
143                 g_warning ("could not create main window");
144                 return FALSE;
145         }
146
147         folder_view = GTK_WIDGET(modest_main_window_folder_tree(priv->modest_acc_mgr,
148                                                                 priv->account_store));
149         priv->folder_view = folder_view;
150         folder_view_holder = glade_xml_get_widget (priv->glade_xml, "folders");
151         if (!folder_view||!folder_view_holder) {
152                 g_warning ("failed to create folder tree");
153                 return FALSE;
154         }
155         gtk_container_add (GTK_CONTAINER(folder_view_holder), folder_view);
156         
157         header_view  =  GTK_WIDGET(modest_main_window_header_tree (NULL));
158         priv->header_view = header_view;
159         header_view_holder = glade_xml_get_widget (priv->glade_xml, "mail_list");
160         if (!header_view) {
161                 g_warning ("failed to create header tree");
162                 return FALSE;
163         }
164         gtk_container_add (GTK_CONTAINER(header_view_holder), header_view);
165
166         g_signal_connect (G_OBJECT(folder_view), "folder_selected",
167                           G_CALLBACK(on_folder_clicked), modest_ui);
168         
169         message_view  = GTK_WIDGET(modest_msg_view_new (NULL));
170         priv->message_view = message_view;
171         if (!message_view) {
172                 g_warning ("failed to create message view");
173                 return FALSE;
174         }
175         //g_signal_connect(G_OBJECT(message_view), "on_mailto_clicked",
176         //            G_CALLBACK(ui_on_mailto_clicked), modest_ui);
177
178         mail_paned = glade_xml_get_widget (priv->glade_xml, "mail_paned");
179         gtk_paned_add2 (GTK_PANED(mail_paned), message_view);
180
181         g_signal_connect (header_view, "message_selected",
182                           G_CALLBACK(on_message_clicked),
183                           modest_ui);
184
185         g_signal_connect (header_view, "status_update",
186                           G_CALLBACK(on_headers_status_update), modest_ui);
187
188         g_signal_connect (header_view, "row-activated",
189                           G_CALLBACK(on_message_activated),
190                           modest_ui);
191
192         account_settings_item = glade_xml_get_widget (priv->glade_xml, "AccountSettingsMenuItem");
193         if (!account_settings_item) {
194                 g_warning ("The account settings item isn't available!\n");
195                 return FALSE;
196         }
197
198         g_signal_connect (account_settings_item, "activate",
199                           G_CALLBACK(account_settings), modest_ui);
200
201         new_account_item = glade_xml_get_widget (priv->glade_xml, "NewAccountWizardMenuItem");
202         if (!new_account_item) {
203                 g_warning ("The new account item isn't available!\n");
204                 return FALSE;
205         }
206
207         g_signal_connect (new_account_item, "activate",
208                 G_CALLBACK(new_wizard_account), modest_ui);
209
210         open_item = glade_xml_get_widget (priv->glade_xml, "open1");
211         if (!open_item) {
212                 g_warning ("The open item isn't available!\n");
213                 return FALSE;
214         }
215         g_signal_connect (open_item, "activate", G_CALLBACK(on_open_message_clicked),
216                           modest_ui);
217
218         delete_item = glade_xml_get_widget (priv->glade_xml, "delete1");
219         if (!delete_item) {
220                 g_warning ("The delete item isn't available!\n");
221                 return FALSE;
222         }
223         g_signal_connect (delete_item, "activate", G_CALLBACK(on_delete_clicked),
224                           modest_ui);
225
226         view_attachments_item = glade_xml_get_widget (priv->glade_xml, "menu_view_attachments");
227         if (!view_attachments_item) {
228                 g_warning ("The view_attachments_item isn't available!");
229                 return FALSE;
230         }
231
232         forward_attached_menu_item = glade_xml_get_widget (priv->glade_xml, "forward_attached");
233         if (!forward_attached_menu_item) {
234                 g_warning ("The forward_attached_menu_item isn't available!");
235                 return FALSE;
236         }
237         g_signal_connect (forward_attached_menu_item, "activate", G_CALLBACK(on_forward_attached_activated),
238                           modest_ui);
239
240         register_toolbar_callbacks (modest_ui);
241
242         modest_window_mgr_register (priv->modest_window_mgr,
243                                     G_OBJECT(win), MODEST_MAIN_WINDOW, 0);
244         g_signal_connect (win, "destroy-event", G_CALLBACK(modest_ui_main_view_destroy),
245                           modest_ui);
246         g_signal_connect (win, "delete-event", G_CALLBACK(modest_ui_main_view_destroy),
247                           modest_ui);
248         gtk_widget_set_usize (GTK_WIDGET(win), width, height);
249         gtk_window_set_title (GTK_WINDOW(win), PACKAGE_STRING);
250
251         gtk_widget_show_all (win);
252         return TRUE;
253 }
254
255
256 static void
257 register_toolbar_callbacks (ModestUI *modest_ui)
258 {
259         ModestUIPrivate *priv;
260         GtkWidget *button;
261
262         g_return_if_fail (modest_ui);
263
264         priv = MODEST_UI_GET_PRIVATE (modest_ui);
265
266         button = glade_xml_get_widget (priv->glade_xml, "toolb_new_mail");
267         if (button)
268                 g_signal_connect (button, "clicked",
269                                   G_CALLBACK(on_new_mail_clicked), modest_ui);
270
271         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply");
272         if (button) {
273                 g_signal_connect (button, "clicked",
274                                   G_CALLBACK(on_reply_clicked), modest_ui);
275                 gtk_widget_set_sensitive(button, FALSE);
276         }
277
278         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply_all");
279         if (button) {
280                 //g_signal_connect (button, "clicked",
281                 //                G_CALLBACK(on_reply_all_clicked), modest_ui);
282                 gtk_widget_set_sensitive(button, FALSE);
283         }
284
285         button = glade_xml_get_widget (priv->glade_xml, "toolb_forward");
286         if (button) {
287                 g_signal_connect (button, "clicked",
288                                   G_CALLBACK(on_forward_clicked), modest_ui);
289                 gtk_widget_set_sensitive(button, FALSE);
290         }
291
292         button = glade_xml_get_widget (priv->glade_xml, "toolb_move_to");
293         if (button) {
294                 //g_signal_connect (button, "clicked",
295                 //                G_CALLBACK(on_move_to_clicked), modest_ui);
296                 gtk_widget_set_sensitive(button, FALSE);
297         }
298
299         button = glade_xml_get_widget (priv->glade_xml, "toolb_delete");
300         if (button) {
301                 g_signal_connect (button, "clicked",
302                                   G_CALLBACK(on_delete_clicked), modest_ui);
303                 gtk_widget_set_sensitive(button, FALSE);
304         }
305
306         button = glade_xml_get_widget (priv->glade_xml, "toolb_send_receive");
307         if (button) {
308                 g_signal_connect (button, "clicked",
309                                   G_CALLBACK(on_sendreceive_button_clicked), modest_ui);
310                 gtk_widget_set_sensitive(button, TRUE);
311         }
312 }
313
314
315 static void
316 on_folder_clicked (ModestFolderView *folder_tree,
317                    TnyMsgFolderIface *folder,
318                    gpointer data)
319 {
320         GtkWidget *win;
321         GtkWidget *button;
322         ModestHeaderView *tree_view;
323         ModestMsgView *msg_view;
324         ModestUIPrivate *priv;
325         GtkWidget *scrollview;
326
327         g_return_if_fail (folder);
328         g_return_if_fail (data);
329
330         priv = MODEST_UI_GET_PRIVATE(data);
331         scrollview = glade_xml_get_widget (priv->glade_xml,"mail_list");
332
333         tree_view = MODEST_HEADER_VIEW (priv->header_view);
334
335         win = glade_xml_get_widget (priv->glade_xml, "main");
336         gtk_window_set_title (GTK_WINDOW(win),
337                               tny_msg_folder_iface_get_name(folder));
338
339         modest_header_view_set_folder (tree_view, folder);
340         priv->current_folder = folder;
341
342         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply");
343         if (button) {
344                 gtk_widget_set_sensitive(button, FALSE);
345         }
346
347         button = glade_xml_get_widget (priv->glade_xml, "toolb_forward");
348         if (button) {
349                 gtk_widget_set_sensitive(button, FALSE);
350         }
351
352         button = glade_xml_get_widget (priv->glade_xml, "toolb_delete");
353         if (button) {
354                 gtk_widget_set_sensitive(button, FALSE);
355         }
356
357         msg_view = MODEST_MSG_VIEW (priv->message_view);
358         g_return_if_fail (msg_view);
359
360         modest_msg_view_set_message  (msg_view, NULL);
361 }
362
363
364 static void
365 on_message_clicked (ModestFolderView *folder_tree,
366                     TnyMsgIface *message,
367                     gpointer data)
368 {
369         GtkWidget *button;
370         ModestMsgView *msg_view;
371         ModestUIPrivate *priv;
372
373         g_return_if_fail (data);
374
375         priv = MODEST_UI_GET_PRIVATE (data);
376         msg_view = MODEST_MSG_VIEW (priv->message_view);
377
378         modest_msg_view_set_message (msg_view, message);
379         
380         button = glade_xml_get_widget (priv->glade_xml, "toolb_reply");
381         if (button) {
382                 gtk_widget_set_sensitive(button, TRUE);
383         }
384         button = glade_xml_get_widget (priv->glade_xml, "toolb_forward");
385         if (button) {
386                 gtk_widget_set_sensitive(button, TRUE);
387         }
388         button = glade_xml_get_widget (priv->glade_xml, "toolb_delete");
389         if (button) {
390                 gtk_widget_set_sensitive(button, TRUE);
391         }
392 }
393
394
395 static GtkWidget*
396 modest_main_window_header_tree (TnyMsgFolderIface *folder)
397 {
398         int i;
399         GSList *columns = NULL;
400         GtkWidget *header_tree;
401         ModestHeaderViewColumn cols[] = {
402                 MODEST_HEADER_VIEW_COLUMN_MSGTYPE,
403                 MODEST_HEADER_VIEW_COLUMN_ATTACH,
404                 MODEST_HEADER_VIEW_COLUMN_FROM,
405                 MODEST_HEADER_VIEW_COLUMN_SUBJECT,
406                 MODEST_HEADER_VIEW_COLUMN_RECEIVED_DATE
407         };
408
409         for (i = 0 ; i != sizeof(cols) / sizeof(ModestHeaderViewColumn); ++i)
410                 columns = g_slist_append (columns, GINT_TO_POINTER(cols[i]));
411
412         header_tree = GTK_WIDGET(modest_header_view_new(folder, columns,
413                                                         MODEST_HEADER_VIEW_STYLE_NORMAL));
414         g_slist_free (columns);
415
416         if (!header_tree) {
417                 g_warning ("could not create header tree");
418                 return NULL;
419         }
420
421         return GTK_WIDGET(header_tree);
422 }
423
424
425 static GtkWidget*
426 modest_main_window_folder_tree (ModestAccountMgr *modest_acc_mgr,
427                                 TnyAccountStoreIface *account_store)
428 {
429         GtkWidget *folder_tree;
430
431         folder_tree = GTK_WIDGET (modest_folder_view_new (account_store));
432         if (!folder_tree) {
433                 g_warning ("could not create folder list");
434                 return NULL;
435         }
436
437         return folder_tree;
438 }
439
440
441 static void
442 on_reply_clicked (GtkWidget *widget, gpointer user_data)
443 {
444         ModestUI *modest_ui = (ModestUI *)user_data;
445
446         quoted_send_msg (modest_ui, QUOTED_SEND_REPLY);
447 }
448
449
450 static void
451 on_forward_clicked (GtkWidget *widget, gpointer user_data)
452 {
453         ModestUI *modest_ui = (ModestUI *)user_data;
454
455         quoted_send_msg (modest_ui, QUOTED_SEND_FORWARD);
456 }
457
458
459 static void
460 on_delete_clicked (GtkWidget *widget, gpointer user_data)
461 {
462         ModestUI *modest_ui = (ModestUI *)user_data;
463         GtkTreeSelection *sel;
464         GtkTreeModel *model;
465         GtkTreeIter iter;
466         GtkTreeModel *mymodel;
467
468         ModestHeaderView *header_view;
469         ModestMsgView *msg_view;
470         ModestUIPrivate *priv;
471
472         g_return_if_fail (modest_ui);
473
474         priv = MODEST_UI_GET_PRIVATE(modest_ui);
475
476         msg_view = MODEST_MSG_VIEW(priv->message_view);
477         g_return_if_fail (msg_view);
478
479         header_view = MODEST_HEADER_VIEW(priv->header_view);
480         g_return_if_fail (header_view);
481
482         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(header_view));
483         g_return_if_fail (sel);
484
485         /* get all selected mails */
486         if (G_LIKELY (gtk_tree_selection_get_selected (sel, &model, &iter))) {
487                 TnyMsgHeaderIface *header;
488
489                 gtk_tree_model_get (model, &iter, TNY_MSG_HEADER_LIST_MODEL_INSTANCE_COLUMN,
490                         &header, -1);
491
492                 if (G_LIKELY (header)) {
493                         TnyMsgFolderIface *folder;
494                         // const TnyMsgIface *msg;
495
496                         if (GTK_IS_TREE_MODEL_SORT (model)) {
497                                 mymodel = gtk_tree_model_sort_get_model
498                                         (GTK_TREE_MODEL_SORT (model));
499                         } else
500                                 mymodel = model;
501
502                         folder = (TnyMsgFolderIface*)tny_msg_header_iface_get_folder (header);
503
504                         /* this will make the message as deleted */
505                         /*      tny_msg_folder_iface_expunge (folder); will finally delete messages */
506                         if (TNY_IS_MSG_FOLDER (folder))
507                                 tny_msg_folder_iface_remove_message (folder, header);
508                         gtk_widget_queue_draw (GTK_WIDGET (header_view));
509                 }
510         }
511 }
512
513
514 static void
515 on_sendreceive_button_clicked (GtkWidget *widget, gpointer user_data)
516 {
517         ModestUI *modest_ui;
518         ModestUIPrivate *priv;
519
520         TnyListIface *store_accounts;
521         TnyIteratorIface *iter;
522         
523         g_return_if_fail (user_data);
524
525         modest_ui = MODEST_UI(user_data);
526         priv = MODEST_UI_GET_PRIVATE(modest_ui);
527
528         store_accounts = tny_list_new (); 
529         tny_account_store_iface_get_accounts (priv->account_store, store_accounts,
530                                               TNY_ACCOUNT_STORE_IFACE_STORE_ACCOUNTS);
531         iter = tny_list_iface_create_iterator (store_accounts);
532         
533         if (tny_iterator_iface_has_first (iter)) {
534                 while (1) {
535                         TnyStoreAccountIface *account;
536                         account = TNY_STORE_ACCOUNT_IFACE(tny_iterator_iface_current(iter));
537                         modest_tny_store_actions_update_folders (account);
538                         
539                         if (!tny_iterator_iface_has_next (iter))
540                                 break;
541                         
542                         tny_iterator_iface_next (iter); 
543                 }
544                 
545         }
546         g_object_unref (G_OBJECT(iter));
547         g_object_unref (G_OBJECT(store_accounts));
548                 
549         if (priv->header_view && priv->current_folder) {
550                 
551                 modest_header_view_set_folder (MODEST_HEADER_VIEW(priv->header_view),
552                                                priv->current_folder);
553                 gtk_widget_queue_draw (priv->header_view);
554         }
555 }
556
557
558 static void
559 on_forward_attached_activated (GtkWidget *widget, gpointer user_data)
560 {
561         ModestUI *modest_ui = (ModestUI *)user_data;
562
563         quoted_send_msg (modest_ui, QUOTED_SEND_FORWARD_ATTACHED);
564 }
565
566 static void
567 on_headers_status_update (GtkWidget *header_view, const gchar *msg, gint status_id,
568                           gpointer user_data)
569 {
570         ModestUIPrivate *priv;
571         ModestUI *modest_ui;
572
573         GtkStatusbar *status_bar;
574         GtkProgressBar *progress_bar;
575         GtkWidget    *status_box;
576         
577         modest_ui = MODEST_UI (user_data);
578         priv      = MODEST_UI_GET_PRIVATE(modest_ui);
579
580         progress_bar = GTK_PROGRESS_BAR(glade_xml_get_widget
581                                         (priv->glade_xml, "progressbar"));
582         status_bar   = GTK_STATUSBAR  (glade_xml_get_widget
583                                        (priv->glade_xml, "statusbar"));
584
585         
586         status_box   = glade_xml_get_widget (priv->glade_xml, "statusbox");
587         
588         
589         if (!status_bar || !progress_bar) {
590                 g_warning ("failed to find status / progress bar");
591                 return;
592         }
593
594         if (msg && status_id) {
595                 gtk_widget_show (status_box);
596                 gtk_progress_bar_pulse (progress_bar);
597                 gtk_statusbar_push (status_bar, status_id, msg);
598         } else {
599                 gtk_widget_hide   (status_box);
600                 gtk_statusbar_pop (status_bar, status_id);
601         }
602 }               
603