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