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