8576e2b6463f5b3e8c7dbb34f97e69c715271ed7
[modest] / src / maemo / modest-main-window.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 #include <glib/gi18n.h>
31 #include <string.h>
32 #include <gtk/gtkaboutdialog.h>
33 #include <gtk/gtktreeviewcolumn.h>
34
35 #include <modest-widget-memory.h>
36 #include <modest-icon-factory.h>
37
38 #include <widgets/modest-toolbar.h>
39
40 #include "modest-main-window.h"
41 #include "modest-account-view-window.h"
42 #include "modest-account-mgr.h"
43 #include "modest-conf.h"
44 #include "modest-edit-msg-window.h"
45 #include "modest-icon-names.h"
46 #include "modest-tny-platform-factory.h"
47 #include "modest-tny-msg-actions.h"
48 #include "modest-mail-operation.h"
49
50 /* 'private'/'protected' functions */
51 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
52 static void modest_main_window_init          (ModestMainWindow *obj);
53 static void modest_main_window_finalize      (GObject *obj);
54
55 static void restore_sizes (ModestMainWindow *self);
56 static void save_sizes (ModestMainWindow *self);
57
58 /* list my signals */
59 enum {
60         /* MY_SIGNAL_1, */
61         /* MY_SIGNAL_2, */
62         LAST_SIGNAL
63 };
64
65 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
66 struct _ModestMainWindowPrivate {
67
68         GtkUIManager *ui_manager;
69
70         GtkWidget *toolbar;
71         GtkWidget *menu;
72
73         //GtkWidget *folder_paned;
74         GtkWidget *msg_paned;
75         GtkWidget *main_paned;
76         
77         ModestWidgetFactory *widget_factory;
78         TnyPlatformFactory *factory;
79   
80         ModestHeaderView *header_view;
81         ModestFolderView *folder_view;
82         ModestMsgView    *msg_preview;
83 };
84
85
86 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
87                                                 MODEST_TYPE_MAIN_WINDOW, \
88                                                 ModestMainWindowPrivate))
89
90
91 typedef struct _GetMsgAsyncHelper {
92         ModestMainWindowPrivate *main_window_private;
93         guint action;
94         ModestMailOperationReplyType reply_type;
95         ModestMailOperationForwardType forward_type;
96         gchar *from;
97 } GetMsgAsyncHelper;
98
99
100 /* globals */
101 static GtkWindowClass *parent_class = NULL;
102
103 /* uncomment the following if you have defined any signals */
104 /* static guint signals[LAST_SIGNAL] = {0}; */
105
106 GType
107 modest_main_window_get_type (void)
108 {
109         static GType my_type = 0;
110         if (!my_type) {
111                 static const GTypeInfo my_info = {
112                         sizeof(ModestMainWindowClass),
113                         NULL,           /* base init */
114                         NULL,           /* base finalize */
115                         (GClassInitFunc) modest_main_window_class_init,
116                         NULL,           /* class finalize */
117                         NULL,           /* class data */
118                         sizeof(ModestMainWindow),
119                         1,              /* n_preallocs */
120                         (GInstanceInitFunc) modest_main_window_init,
121                         NULL
122                 };
123                 my_type = g_type_register_static (HILDON_TYPE_WINDOW,
124                                                   "ModestMainWindow",
125                                                   &my_info, 0);
126         }
127         return my_type;
128 }
129
130 static void
131 modest_main_window_class_init (ModestMainWindowClass *klass)
132 {
133         GObjectClass *gobject_class;
134         gobject_class = (GObjectClass*) klass;
135
136         parent_class            = g_type_class_peek_parent (klass);
137         gobject_class->finalize = modest_main_window_finalize;
138
139         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
140
141         /* signal definitions go here, e.g.: */
142 /*      signals[MY_SIGNAL_1] = */
143 /*              g_signal_new ("my_signal_1",....); */
144 /*      signals[MY_SIGNAL_2] = */
145 /*              g_signal_new ("my_signal_2",....); */
146 /*      etc. */
147 }
148
149 static void
150 modest_main_window_init (ModestMainWindow *obj)
151 {
152         ModestMainWindowPrivate *priv;
153
154         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
155         
156         priv->factory = modest_tny_platform_factory_get_instance ();
157 }
158
159 static void
160 modest_main_window_finalize (GObject *obj)
161 {
162         ModestMainWindowPrivate *priv;  
163         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
164         if (priv->widget_factory) {
165                 g_object_unref (G_OBJECT(priv->widget_factory));
166                 priv->widget_factory = NULL;
167         }
168
169         G_OBJECT_CLASS(parent_class)->finalize (obj);
170 }
171
172
173 static void
174 on_menu_about (GtkWidget *widget, gpointer data)
175 {
176         GtkWidget *about;
177         const gchar *authors[] = {
178                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
179                 NULL
180         };      
181         about = gtk_about_dialog_new ();
182         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
183         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
184         gtk_about_dialog_set_copyright (
185                 GTK_ABOUT_DIALOG(about),
186                 _("Copyright (c) 2006, Nokia Corporation\n"
187                   "All rights reserved."));
188         gtk_about_dialog_set_comments ( GTK_ABOUT_DIALOG(about),
189                 _("a modest e-mail client\n\n"
190                   "design and implementation: Dirk-Jan C. Binnema\n"
191                   "contributions from the fine people at KernelConcepts and Igalia\n\n"
192                   "uses the tinymail email framework written by Philip van Hoof"));
193         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
194         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
195
196         gtk_dialog_run (GTK_DIALOG (about));
197         gtk_widget_destroy(about);
198 }
199
200
201 static void
202 on_menu_accounts (ModestMainWindow *self, guint action, GtkWidget *widget)
203 {
204         GtkWidget *account_win;
205         ModestMainWindowPrivate *priv;
206
207         g_return_if_fail (widget);
208         g_return_if_fail (self);
209         
210         priv        = MODEST_MAIN_WINDOW_GET_PRIVATE(self);     
211         account_win = modest_account_view_window_new (priv->widget_factory);
212
213         gtk_window_set_transient_for (GTK_WINDOW(account_win),
214                                       GTK_WINDOW(self));
215                                       
216         gtk_widget_show (account_win);
217 }
218
219
220 static void
221 on_menu_new_message (ModestMainWindow *self, guint action, GtkWidget *widget)
222 {
223         GtkWidget *msg_win;
224         ModestMainWindowPrivate *priv;
225
226         priv  = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
227
228         msg_win = modest_edit_msg_window_new (priv->widget_factory,
229                                               MODEST_EDIT_TYPE_NEW,
230                                               NULL);
231         gtk_widget_show (msg_win);
232 }
233
234 static void
235 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
236 {
237         GtkWidget *msg_win;
238         TnyHeader *new_header;
239         TnyMsg *new_msg;
240         ModestMainWindowPrivate *priv;
241         ModestEditType edit_type = -2;
242         GetMsgAsyncHelper *helper;
243
244         helper = (GetMsgAsyncHelper *) (user_data);
245         priv  = helper->main_window_private;
246
247         /* FIXME: select proper action */
248         new_msg = NULL;
249         switch (helper->action) {
250         case 1:
251                 new_msg = 
252                         modest_mail_operation_create_reply_mail (msg, helper->from, helper->reply_type,
253                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
254                 edit_type = MODEST_EDIT_TYPE_REPLY;
255                 break;
256         case 2:
257                 new_msg = 
258                         modest_mail_operation_create_reply_mail (msg, helper->from, helper->reply_type,
259                                                                  MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
260                 edit_type = MODEST_EDIT_TYPE_REPLY;
261                 break;
262         case 3:
263                 new_msg = 
264                         modest_mail_operation_create_forward_mail (msg, helper->from, helper->forward_type);
265                 edit_type = MODEST_EDIT_TYPE_FORWARD;
266                 break;
267         default:
268                 g_warning ("unexpected action type: %d", helper->action);
269         }
270         
271         if (new_msg) {
272                 /* Set from */
273                 new_header = tny_msg_get_header (new_msg);
274                 tny_header_set_from (new_header, helper->from);
275                 
276                 /* Show edit window */
277                 msg_win = modest_edit_msg_window_new (priv->widget_factory,
278                                                       edit_type,
279                                                       new_msg);
280                 gtk_widget_show (msg_win);
281                 
282                 /* Clean and go on */
283                 g_object_unref (new_msg);
284         }
285 }
286
287 static void
288 on_menu_reply_forward (ModestMainWindow *self, guint action, GtkWidget *widget)
289 {
290         ModestMainWindowPrivate *priv;
291         ModestHeaderView *header_view;
292         TnyList *header_list;
293         TnyIterator *iter;
294         gchar *reply_key, *forward_key;
295         ModestMailOperationReplyType reply_type;
296         ModestMailOperationForwardType forward_type;
297         ModestConf *conf;
298         GError *error;
299         GetMsgAsyncHelper *helper;
300
301         priv  = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
302         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->factory);
303
304         header_view = modest_widget_factory_get_header_view (priv->widget_factory);
305         header_list = modest_header_view_get_selected_headers (header_view);
306
307         /* Get reply and forward types */
308         error = NULL;
309         reply_key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, MODEST_CONF_REPLY_TYPE);
310         reply_type = modest_conf_get_int (conf, reply_key, &error);
311         if (error || reply_type == 0) {
312                 g_warning ("key %s not defined", reply_key);
313                 reply_type = MODEST_MAIL_OPERATION_REPLY_TYPE_CITE;
314                 if (error) {
315                         g_error_free (error);
316                         error = NULL;
317                 }
318         }
319         g_free (reply_key);
320         
321         forward_key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, MODEST_CONF_FORWARD_TYPE);
322         forward_type = modest_conf_get_int (conf, forward_key, &error);
323         if (error || forward_type == 0) {
324                 g_warning ("key %s not defined", forward_key);
325                 forward_type = MODEST_MAIL_OPERATION_FORWARD_TYPE_INLINE;
326                 if (error) {
327                         g_error_free (error);
328                         error = NULL;
329                 }
330         }
331         g_free (forward_key);
332         
333         if (header_list) {
334                 TnyHeader *header;
335                 TnyFolder *folder;
336                 gchar *from, *email_key;
337                 const gchar *account_name;
338
339                 /* We assume that we can only select messages of the
340                    same folder and that we reply all of them from the
341                    same account. In fact the interface currently only
342                    allows single selection */
343                 account_name = modest_folder_view_get_selected_account (priv->folder_view);
344                 email_key = g_strdup_printf ("%s/%s/%s", MODEST_ACCOUNT_NAMESPACE, 
345                                              account_name, MODEST_ACCOUNT_EMAIL);
346                 from = modest_conf_get_string (conf, email_key, NULL);
347                 g_free (email_key);
348
349                 iter = tny_list_create_iterator (header_list);
350                 header = TNY_HEADER (tny_iterator_get_current (iter));
351                 folder = tny_header_get_folder (header);
352
353                 do {
354                         /* Since it's not an object, we need to create
355                            it each time due to it's not a GObject and
356                            we can not do a g_object_ref. No need to
357                            free it, tinymail will do it for us. */
358                         helper = g_slice_new0 (GetMsgAsyncHelper);
359                         helper->main_window_private = priv;
360                         helper->reply_type = reply_type;
361                         helper->forward_type = forward_type;
362                         helper->action = action;
363                         helper->from = from;
364
365                         /* Get msg from header */
366                         header = TNY_HEADER (tny_iterator_get_current (iter));
367                         tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
368                         tny_iterator_next (iter);
369
370                 } while (!tny_iterator_is_done (iter));
371
372                 /* Clean */
373                 g_free (from);
374                 g_object_unref (G_OBJECT (iter));
375                 g_object_unref (G_OBJECT (folder));
376         }
377 }
378
379 static void
380 on_menu_quit (ModestMainWindow *self, guint action, GtkWidget *widget)
381 {
382         save_sizes (self);
383         gtk_widget_destroy (GTK_WIDGET(self));
384 }
385
386 static void
387 on_menu_delete (ModestMainWindow *self, guint action, GtkWidget *widget)
388 {
389         ModestMainWindowPrivate *priv;
390         ModestHeaderView *header_view;
391         TnyList *header_list;
392         TnyIterator *iter;
393         GtkTreeModel *model;
394
395         priv  = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
396
397         header_view = modest_widget_factory_get_header_view (priv->widget_factory);
398         header_list = modest_header_view_get_selected_headers (header_view);
399         
400         if (header_list) {
401                 iter = tny_list_create_iterator (header_list);
402                 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
403                 if (GTK_IS_TREE_MODEL_SORT (model))
404                         model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
405                 do {
406                         TnyHeader *header;
407                         ModestMailOperation *mail_op;
408
409                         header = TNY_HEADER (tny_iterator_get_current (iter));
410                         /* TODO: thick grain mail operation involving
411                            a list of objects. Composite pattern ??? */
412                         mail_op = modest_mail_operation_new ();
413
414                         /* Move to trash */
415                         modest_mail_operation_remove_msg (mail_op, header, TRUE);
416
417                         /* Remove from tree model */
418                         tny_list_remove (TNY_LIST (model), G_OBJECT (header));
419
420                         g_object_unref (G_OBJECT (mail_op));
421                         g_object_unref (header);
422                         tny_iterator_next (iter);
423
424                 } while (!tny_iterator_is_done (iter));
425         }
426 }
427
428
429 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
430 static const gchar* UI_DEF=
431 //      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
432         "<ui>"
433         "  <popup>"
434         "    <menu name=\"Message\" action=\"MenuMessage\">"
435         "      <menuitem name=\"New\" action=\"on_menu_new_message\" />"
436         "    </menu>"
437         "    <menu name=\"JustifyMenu\" action=\"JustifyMenuAction\">"
438         "      <menuitem name=\"Left\" action=\"justify-left\"/>"
439         "      <menuitem name=\"Centre\" action=\"justify-center\"/>"
440         "      <menuitem name=\"Right\" action=\"justify-right\"/>"
441         "      <menuitem name=\"Fill\" action=\"justify-fill\"/>"
442         "    </menu>"
443         "  </popup>"
444         "</ui>";
445
446 static GtkMenu *
447 get_menu (ModestMainWindow *self)
448 {
449         GtkWidget *w;
450         GError *err = NULL;
451         int i = 0;
452         
453         ModestMainWindowPrivate *priv;
454         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
455
456         priv->ui_manager = gtk_ui_manager_new ();
457
458         if (!gtk_ui_manager_add_ui_from_string (priv->ui_manager,
459                                                 UI_DEF, strlen(UI_DEF),
460                                                 &err)) {
461                 g_warning (err->message);
462                 g_error_free (err);
463         }
464         
465         w = gtk_ui_manager_get_widget (priv->ui_manager, "/ui/popup");
466         return GTK_MENU(w);
467 }
468
469
470
471 static ModestHeaderView*
472 header_view_new (ModestMainWindow *self)
473 {
474         int i;
475         GList *columns = NULL;
476         ModestHeaderView *header_view;
477         ModestMainWindowPrivate *priv;
478         ModestHeaderViewColumn cols[] = {
479                 MODEST_HEADER_VIEW_COLUMN_MSGTYPE,
480                 MODEST_HEADER_VIEW_COLUMN_ATTACH,
481                 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER
482 //              MODEST_HEADER_VIEW_COLUMN_FROM,
483 //              MODEST_HEADER_VIEW_COLUMN_SUBJECT,
484 //              MODEST_HEADER_VIEW_COLUMN_RECEIVED_DATE
485         };
486         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
487         
488         for (i = 0 ; i != sizeof(cols) / sizeof(ModestHeaderViewColumn); ++i)
489                 columns = g_list_append (columns, GINT_TO_POINTER(cols[i]));
490
491         header_view = modest_widget_factory_get_header_view (priv->widget_factory);
492         modest_header_view_set_columns (header_view, columns);
493         g_list_free (columns);
494
495         return header_view;
496 }
497
498
499 static void
500 on_toolbar_button_clicked (ModestToolbar *toolbar, ModestToolbarButton button_id,
501                            ModestMainWindow *self)
502 {
503         GtkTreeSelection *sel;
504         GtkTreeIter iter;
505         GtkTreeModel *model;
506         ModestMainWindowPrivate *priv;
507
508         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
509         
510         switch (button_id) {
511         case MODEST_TOOLBAR_BUTTON_NEW_MAIL:
512                 on_menu_new_message (self, 0, NULL);
513                 break;
514         case MODEST_TOOLBAR_BUTTON_REPLY:
515                 on_menu_reply_forward (self, 1, NULL);
516                 break;
517         case MODEST_TOOLBAR_BUTTON_REPLY_ALL:
518                 on_menu_reply_forward (self, 2, NULL);
519                 break;
520         case MODEST_TOOLBAR_BUTTON_FORWARD:
521                 on_menu_reply_forward (self, 3, NULL);
522                 break;
523         case MODEST_TOOLBAR_BUTTON_SEND_RECEIVE:
524                 
525
526         case MODEST_TOOLBAR_BUTTON_NEXT:
527                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->header_view));
528                 if (sel) {
529                         gtk_tree_selection_get_selected (sel, &model, &iter);
530                         gtk_tree_model_iter_next (model, &iter);
531                         gtk_tree_selection_select_iter (sel, &iter);
532                 }
533                 
534         case MODEST_TOOLBAR_BUTTON_PREV:
535         /*      if (sel) { */
536 /*                      gtk_tree_selection_get_selected (sel, &model, &iter); */
537 /*                      gtk_tree_model_iter_prev (model, &iter); */
538 /*                      gtk_tree_selection_select_iter (sel, &iter); */
539 /*              } */
540
541                 break;
542         case MODEST_TOOLBAR_BUTTON_DELETE:
543                 on_menu_delete (self, 0, GTK_WIDGET (toolbar));
544                 break;
545
546         default:
547                 g_printerr ("modest: key %d pressed\n", button_id);
548         }
549 }
550
551 static ModestToolbar*
552 toolbar_new (ModestMainWindow *self)
553 {
554         int i;
555         ModestToolbar *toolbar;
556         GSList *buttons = NULL;
557         ModestMainWindowPrivate *priv;
558
559         ModestToolbarButton button_ids[] = {
560                 MODEST_TOOLBAR_BUTTON_NEW_MAIL,
561                 MODEST_TOOLBAR_BUTTON_REPLY,
562                 MODEST_TOOLBAR_BUTTON_REPLY_ALL,
563                 MODEST_TOOLBAR_BUTTON_FORWARD,
564                 MODEST_TOOLBAR_SEPARATOR,
565                 MODEST_TOOLBAR_BUTTON_SEND_RECEIVE,
566                 MODEST_TOOLBAR_SEPARATOR,
567                 MODEST_TOOLBAR_BUTTON_PREV,
568                 MODEST_TOOLBAR_BUTTON_NEXT,
569                 MODEST_TOOLBAR_SEPARATOR,               
570                 MODEST_TOOLBAR_BUTTON_DELETE
571         };              
572         
573         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
574
575         for (i = 0 ; i != sizeof(button_ids) / sizeof(ModestToolbarButton); ++i)
576                 buttons = g_slist_append (buttons, GINT_TO_POINTER(button_ids[i]));
577         
578         toolbar = modest_widget_factory_get_main_toolbar (priv->widget_factory, buttons);
579         g_slist_free (buttons);
580         
581         g_signal_connect (G_OBJECT(toolbar), "button_clicked",
582                           G_CALLBACK(on_toolbar_button_clicked), self);
583         
584         return toolbar;
585 }
586
587
588
589 static void
590 restore_sizes (ModestMainWindow *self)
591 {
592         ModestConf *conf;
593         ModestMainWindowPrivate *priv;
594         
595         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
596         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->factory);
597
598         modest_widget_memory_restore (conf,G_OBJECT(self),
599                                                "modest-main-window");
600         modest_widget_memory_restore (conf, G_OBJECT(priv->msg_paned),
601                                                "modest-msg-paned");
602         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
603                                                "modest-main-paned");
604 }
605
606
607 static void
608 save_sizes (ModestMainWindow *self)
609 {
610         ModestMainWindowPrivate *priv;
611         ModestConf *conf;
612         
613         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
614         conf = modest_tny_platform_factory_get_modest_conf_instance (priv->factory);
615         
616         modest_widget_memory_save (conf,G_OBJECT(self),
617                                             "modest-main-window");
618         modest_widget_memory_save (conf, G_OBJECT(priv->msg_paned),
619                                             "modest-msg-paned");
620         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
621                                             "modest-main-paned");
622 }
623
624 static GtkWidget*
625 wrapped_in_scrolled_window (GtkWidget *widget, gboolean needs_viewport)
626 {
627         GtkWidget *win;
628
629         win = gtk_scrolled_window_new (NULL, NULL);
630         gtk_scrolled_window_set_policy
631                 (GTK_SCROLLED_WINDOW (win),GTK_POLICY_NEVER,
632                  GTK_POLICY_AUTOMATIC);
633         
634         if (needs_viewport)
635                 gtk_scrolled_window_add_with_viewport
636                         (GTK_SCROLLED_WINDOW(win), widget);
637         else
638                 gtk_container_add (GTK_CONTAINER(win),
639                                    widget);
640
641         return win;
642 }
643
644
645 static gboolean
646 on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self)
647 {
648         save_sizes (self);
649         return FALSE;
650 }
651
652
653 GtkWidget*
654 modest_main_window_new (ModestWidgetFactory *widget_factory)
655 {
656         GObject *obj;
657         ModestMainWindowPrivate *priv;
658         
659         GtkWidget *main_vbox;
660         GtkWidget *status_hbox;
661         GtkWidget *header_win, *folder_win, *favorites_win;
662         
663         g_return_val_if_fail (widget_factory, NULL);
664
665         obj  = g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL);
666         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
667
668         g_object_ref (widget_factory);
669         priv->widget_factory = widget_factory;
670
671         /* widgets from factory */
672         priv->folder_view = modest_widget_factory_get_folder_view (widget_factory);
673         priv->header_view = header_view_new (MODEST_MAIN_WINDOW(obj));
674         priv->msg_preview = modest_widget_factory_get_msg_preview (widget_factory);
675         
676         folder_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->folder_view),
677                                                  FALSE);
678         header_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->header_view),
679                                                  FALSE);                                
680         /*menu */
681         priv->menu = get_menu (MODEST_MAIN_WINDOW(obj));
682         hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(priv->menu));
683         
684         priv->toolbar = GTK_WIDGET(toolbar_new (MODEST_MAIN_WINDOW(obj)));
685         
686         /* paned */
687         priv->msg_paned = gtk_vpaned_new ();
688         priv->main_paned = gtk_hpaned_new ();
689
690         gtk_paned_add1 (GTK_PANED(priv->main_paned), folder_win);
691         gtk_paned_add2 (GTK_PANED(priv->main_paned), priv->msg_paned);
692
693         gtk_paned_add1 (GTK_PANED(priv->msg_paned), header_win);
694         gtk_paned_add2 (GTK_PANED(priv->msg_paned), GTK_WIDGET(priv->msg_preview));
695
696         gtk_widget_show (GTK_WIDGET(priv->header_view));
697         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
698
699         /* status bar / progress */
700         status_hbox = gtk_hbox_new (FALSE, 0);
701         gtk_box_pack_start (GTK_BOX(status_hbox),
702                             modest_widget_factory_get_folder_info_label (widget_factory),
703                             FALSE,FALSE, 6);
704         gtk_box_pack_start (GTK_BOX(status_hbox),
705                             modest_widget_factory_get_status_bar(widget_factory),
706                             TRUE, TRUE, 0);
707         gtk_box_pack_start (GTK_BOX(status_hbox),
708                             modest_widget_factory_get_progress_bar(widget_factory),
709                             FALSE, FALSE, 0);
710         gtk_box_pack_start (GTK_BOX(status_hbox),
711                           modest_widget_factory_get_online_toggle(widget_factory),
712                           FALSE, FALSE, 0);
713
714         /* putting it all together... */
715         main_vbox = gtk_vbox_new (FALSE, 6);
716         gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_paned, TRUE, TRUE,0);
717         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);        
718         gtk_box_pack_start (GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 0);
719         
720         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
721         restore_sizes (MODEST_MAIN_WINDOW(obj));        
722
723         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
724         gtk_window_set_icon  (GTK_WINDOW(obj),
725                               modest_icon_factory_get_icon (MODEST_APP_ICON));
726         
727         gtk_widget_show_all (main_vbox);
728
729         g_signal_connect (G_OBJECT(obj), "delete-event",
730                           G_CALLBACK(on_delete_event), obj);
731         
732         return GTK_WIDGET(obj);
733 }