c0e83763d3d479abef07244240c838504ed0761b
[modest] / src / gtk2 / 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 <modest-widget-memory.h>
31 #include <modest-icon-factory.h>
32
33 #include <widgets/modest-toolbar.h>
34
35 #include "modest-main-window.h"
36 #include "modest-account-view-window.h"
37 #include "modest-edit-msg-window.h"
38 #include "modest-icon-names.h"
39
40
41 /* 'private'/'protected' functions */
42 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
43 static void modest_main_window_init          (ModestMainWindow *obj);
44 static void modest_main_window_finalize      (GObject *obj);
45
46 static void restore_sizes (ModestMainWindow *self);
47 static void save_sizes (ModestMainWindow *self);
48
49 /* list my signals */
50 enum {
51         /* MY_SIGNAL_1, */
52         /* MY_SIGNAL_2, */
53         LAST_SIGNAL
54 };
55
56 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
57 struct _ModestMainWindowPrivate {
58
59         GtkWidget *toolbar;
60         GtkWidget *menubar;
61
62         GtkWidget *folder_paned;
63         GtkWidget *msg_paned;
64         GtkWidget *main_paned;
65         
66         ModestWidgetFactory *factory;
67         ModestConf *conf;
68         ModestAccountMgr *account_mgr;
69         
70         ModestHeaderView *header_view;
71         ModestFolderView *folder_view;
72         ModestMsgView    *msg_preview;
73 };
74
75
76 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
77                                                 MODEST_TYPE_MAIN_WINDOW, \
78                                                 ModestMainWindowPrivate))
79 /* globals */
80 static GtkWindowClass *parent_class = NULL;
81
82 /* uncomment the following if you have defined any signals */
83 /* static guint signals[LAST_SIGNAL] = {0}; */
84
85 GType
86 modest_main_window_get_type (void)
87 {
88         static GType my_type = 0;
89         if (!my_type) {
90                 static const GTypeInfo my_info = {
91                         sizeof(ModestMainWindowClass),
92                         NULL,           /* base init */
93                         NULL,           /* base finalize */
94                         (GClassInitFunc) modest_main_window_class_init,
95                         NULL,           /* class finalize */
96                         NULL,           /* class data */
97                         sizeof(ModestMainWindow),
98                         1,              /* n_preallocs */
99                         (GInstanceInitFunc) modest_main_window_init,
100                         NULL
101                 };
102                 my_type = g_type_register_static (GTK_TYPE_WINDOW,
103                                                   "ModestMainWindow",
104                                                   &my_info, 0);
105         }
106         return my_type;
107 }
108
109 static void
110 modest_main_window_class_init (ModestMainWindowClass *klass)
111 {
112         GObjectClass *gobject_class;
113         gobject_class = (GObjectClass*) klass;
114
115         parent_class            = g_type_class_peek_parent (klass);
116         gobject_class->finalize = modest_main_window_finalize;
117
118         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
119
120         /* signal definitions go here, e.g.: */
121 /*      signals[MY_SIGNAL_1] = */
122 /*              g_signal_new ("my_signal_1",....); */
123 /*      signals[MY_SIGNAL_2] = */
124 /*              g_signal_new ("my_signal_2",....); */
125 /*      etc. */
126 }
127
128 static void
129 modest_main_window_init (ModestMainWindow *obj)
130 {
131         ModestMainWindowPrivate *priv;
132
133         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
134
135         priv->factory = NULL;
136         priv->conf           = NULL;
137         priv->account_mgr    = NULL;
138 }
139
140 static void
141 modest_main_window_finalize (GObject *obj)
142 {
143         ModestMainWindowPrivate *priv;  
144         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
145         if (priv->factory) {
146                 g_object_unref (G_OBJECT(priv->factory));
147                 priv->factory = NULL;
148         }
149         if (priv->conf) {
150                 g_object_unref (G_OBJECT(priv->conf));
151                 priv->conf = NULL;
152         }               
153
154         if (priv->account_mgr) {
155                 g_object_unref (G_OBJECT(priv->account_mgr));
156                 priv->account_mgr = NULL;
157         }               
158
159         G_OBJECT_CLASS(parent_class)->finalize (obj);
160 }
161
162
163 static void
164 on_menu_about (GtkWidget *widget, gpointer data)
165 {
166         GtkWidget *about;
167         const gchar *authors[] = {
168                 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
169                 NULL
170         };      
171         about = gtk_about_dialog_new ();
172         gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
173         gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
174         gtk_about_dialog_set_copyright (
175                 GTK_ABOUT_DIALOG(about),
176                 _("Copyright (c) 2006, Nokia Corporation\n"
177                   "All rights reserved."));
178         gtk_about_dialog_set_comments ( GTK_ABOUT_DIALOG(about),
179                 _("a modest e-mail client\n\n"
180                   "design and implementation: Dirk-Jan C. Binnema\n"
181                   "contributions from the fine people at KernelConcepts\n\n"
182                   "uses the tinymail email framework written by Philip van Hoof"));
183         gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
184         gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
185
186         gtk_dialog_run (GTK_DIALOG (about));
187         gtk_widget_destroy(about);
188 }
189
190
191 static void
192 on_menu_accounts (ModestMainWindow *self, guint action, GtkWidget *widget)
193 {
194         GtkWidget *account_win;
195         ModestMainWindowPrivate *priv;
196
197         g_return_if_fail (widget);
198         g_return_if_fail (self);
199         
200         priv        = MODEST_MAIN_WINDOW_GET_PRIVATE(self);     
201         account_win = modest_account_view_window_new (priv->account_mgr,
202                                                       priv->factory);
203
204         gtk_window_set_transient_for (GTK_WINDOW(account_win),
205                                       GTK_WINDOW(self));
206                                       
207         gtk_widget_show (account_win);
208 }
209
210
211 static void
212 on_menu_new_message (ModestMainWindow *self, guint action, GtkWidget *widget)
213 {
214         GtkWidget *msg_win;
215         ModestMainWindowPrivate *priv;
216
217         priv  = MODEST_MAIN_WINDOW_GET_PRIVATE(self);   
218
219         msg_win = modest_edit_msg_window_new (priv->conf,
220                                               priv->factory,
221                                               MODEST_EDIT_TYPE_NEW,
222                                               NULL);
223         gtk_widget_show (msg_win);
224 }
225
226 static void
227 on_menu_quit (ModestMainWindow *self, guint action, GtkWidget *widget)
228 {
229         save_sizes (self);
230         gtk_widget_destroy (GTK_WIDGET(self));
231 }
232
233
234 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
235 static GtkItemFactoryEntry menu_items[] = {
236         { "/_File",             NULL,                   NULL,           0, "<Branch>" },
237         { "/File/_New",         "<control>N",           NULL,           0, "<StockItem>", GTK_STOCK_NEW },
238         { "/File/_Open",        "<control>O",           NULL,           0, "<StockItem>", GTK_STOCK_OPEN },
239         { "/File/_Save",        "<control>S",           NULL,           0, "<StockItem>", GTK_STOCK_SAVE },
240         { "/File/Save _As",     NULL,                   NULL,           0, "<Item>" },
241         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" },
242         { "/File/_Quit",        "<CTRL>Q",              on_menu_quit,  0, "<StockItem>", GTK_STOCK_QUIT },
243
244         { "/_Edit",             NULL,                   NULL,           0, "<Branch>" },
245         { "/Edit/_Undo",        "<CTRL>Z",              NULL,           0, "<StockItem>", GTK_STOCK_UNDO },
246         { "/Edit/_Redo",        "<shift><CTRL>Z",       NULL,           0, "<StockItem>", GTK_STOCK_REDO },
247         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" },
248         { "/Edit/Cut",          "<control>X",           NULL,           0, "<StockItem>", GTK_STOCK_CUT  },
249         { "/Edit/Copy",         "<CTRL>C",              NULL,           0, "<StockItem>", GTK_STOCK_COPY },
250         { "/Edit/Paste",        NULL,                   NULL,           0, "<StockItem>", GTK_STOCK_PASTE},
251         { "/Edit/sep1",         NULL,                   NULL,           0, "<Separator>" },
252         { "/Edit/Delete",       "<CTRL>Q",              NULL,           0, "<Item>" },
253         { "/Edit/Select all",   "<CTRL>A",              NULL,           0, "<Item>" },
254         { "/Edit/Deelect all",  "<Shift><CTRL>A",       NULL,           0, "<Item>" },
255
256         { "/_Actions",                NULL,             NULL,           0, "<Branch>" },
257         { "/Actions/_New Message",    NULL,             on_menu_new_message,            0, "<Item>" },
258         { "/Actions/_Reply",    NULL,                   NULL,           0, "<Item>" },
259         { "/Actions/_Forward",  NULL,                   NULL,           0, "<Item>" },
260         { "/Actions/_Bounce",   NULL,                   NULL,           0, "<Item>" },  
261         
262         { "/_Options",           NULL,                  NULL,           0, "<Branch>" },
263         { "/Options/_Accounts",  NULL,                  on_menu_accounts,0, "<Item>" },
264         { "/Options/_Contacts",  NULL,                  NULL,           0, "<Item>" },
265
266
267         { "/_Help",         NULL,                       NULL,           0, "<Branch>" },
268         { "/_Help/About",   NULL,                       on_menu_about,  0, "<StockItem>", GTK_STOCK_ABOUT},
269 };
270
271 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
272
273
274 static GtkWidget *
275 menubar_new (ModestMainWindow *self)
276 {
277         GtkItemFactory *item_factory;
278         GtkAccelGroup *accel_group;
279         
280         /* Make an accelerator group (shortcut keys) */
281         accel_group = gtk_accel_group_new ();
282         
283         /* Make an ItemFactory (that makes a menubar) */
284         item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
285                                              accel_group);
286         
287         /* This function generates the menu items. Pass the item factory,
288            the number of items in the array, the array itself, and any
289            callback data for the the menu items. */
290         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, self);
291         
292         ///* Attach the new accelerator group to the window. */
293         gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
294         
295         /* Finally, return the actual menu bar created by the item factory. */
296         return gtk_item_factory_get_widget (item_factory, "<main>");
297 }
298
299
300
301
302 static ModestHeaderView*
303 header_view_new (ModestMainWindow *self)
304 {
305         int i;
306         GSList *columns = NULL;
307         ModestHeaderView *header_view;
308         ModestMainWindowPrivate *priv;
309         ModestHeaderViewColumn cols[] = {
310                 MODEST_HEADER_VIEW_COLUMN_MSGTYPE,
311                 MODEST_HEADER_VIEW_COLUMN_ATTACH,
312                 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER
313 /*              MODEST_HEADER_VIEW_COLUMN_FROM, */
314 /*              MODEST_HEADER_VIEW_COLUMN_SUBJECT, */
315 /*              MODEST_HEADER_VIEW_COLUMN_RECEIVED_DATE */
316         };
317         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
318         
319         for (i = 0 ; i != sizeof(cols) / sizeof(ModestHeaderViewColumn); ++i)
320                 columns = g_slist_append (columns, GINT_TO_POINTER(cols[i]));
321
322         header_view = modest_widget_factory_get_header_view (priv->factory);
323         modest_header_view_set_columns (header_view, columns);
324         g_slist_free (columns);
325
326         return header_view;
327 }
328
329 static ModestToolbar*
330 toolbar_new (ModestMainWindow *self)
331 {
332         int i;
333         ModestToolbar *toolbar;
334         GSList *buttons = NULL;
335         ModestMainWindowPrivate *priv;
336
337         ModestToolbarButton button_ids[] = {
338                 MODEST_TOOLBAR_BUTTON_NEW_MAIL,
339                 MODEST_TOOLBAR_BUTTON_REPLY,
340                 MODEST_TOOLBAR_BUTTON_REPLY_ALL,
341                 MODEST_TOOLBAR_BUTTON_FORWARD,
342                 MODEST_TOOLBAR_SEPARATOR,
343                 MODEST_TOOLBAR_BUTTON_SEND_RECEIVE,
344                 MODEST_TOOLBAR_SEPARATOR,
345                 MODEST_TOOLBAR_BUTTON_NEXT,
346                 MODEST_TOOLBAR_BUTTON_PREV,
347                 MODEST_TOOLBAR_SEPARATOR,               
348                 MODEST_TOOLBAR_BUTTON_DELETE
349         };              
350         
351         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
352
353         for (i = 0 ; i != sizeof(button_ids) / sizeof(ModestToolbarButton); ++i)
354                 buttons = g_slist_append (buttons, GINT_TO_POINTER(button_ids[i]));
355         
356         toolbar = modest_widget_factory_get_main_toolbar (priv->factory, buttons);
357         g_slist_free (buttons);
358         
359         return toolbar;
360 }
361
362
363
364 static void
365 restore_sizes (ModestMainWindow *self)
366 {
367         ModestMainWindowPrivate *priv;  
368         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
369         
370         modest_widget_memory_restore_settings (priv->conf,GTK_WIDGET(self),
371                                                "modest-main-window");
372         modest_widget_memory_restore_settings (priv->conf, GTK_WIDGET(priv->folder_paned),
373                                                "modest-folder-paned");
374         modest_widget_memory_restore_settings (priv->conf, GTK_WIDGET(priv->msg_paned),
375                                                "modest-msg-paned");
376         modest_widget_memory_restore_settings (priv->conf, GTK_WIDGET(priv->main_paned),
377                                                "modest-main-paned");
378 }
379
380
381 static void
382 save_sizes (ModestMainWindow *self)
383 {
384         ModestMainWindowPrivate *priv;
385         
386         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
387         
388         modest_widget_memory_save_settings (priv->conf,GTK_WIDGET(self),
389                                             "modest-main-window");
390         modest_widget_memory_save_settings (priv->conf, GTK_WIDGET(priv->folder_paned),
391                                             "modest-folder-paned");
392         modest_widget_memory_save_settings (priv->conf, GTK_WIDGET(priv->msg_paned),
393                                             "modest-msg-paned");
394         modest_widget_memory_save_settings (priv->conf, GTK_WIDGET(priv->main_paned),
395                                             "modest-main-paned");
396 }
397
398 static GtkWidget*
399 wrapped_in_scrolled_window (GtkWidget *widget, gboolean needs_viewport)
400 {
401         GtkWidget *win;
402
403         win = gtk_scrolled_window_new (NULL, NULL);
404         gtk_scrolled_window_set_policy
405                 (GTK_SCROLLED_WINDOW (win),GTK_POLICY_NEVER,
406                  GTK_POLICY_AUTOMATIC);
407         
408         if (needs_viewport)
409                 gtk_scrolled_window_add_with_viewport
410                         (GTK_SCROLLED_WINDOW(win), widget);
411         else
412                 gtk_container_add (GTK_CONTAINER(win),
413                                    widget);
414
415         return win;
416 }
417
418
419 static gboolean
420 on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self)
421 {
422         save_sizes (self);
423         return FALSE;
424 }
425
426 static GtkWidget*
427 favorites_view ()
428 {
429         GtkWidget *favorites;
430         GtkTreeStore *store;
431         GtkTreeViewColumn *col;
432
433         store = gtk_tree_store_new (1, G_TYPE_STRING);
434         favorites = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store));
435         col = gtk_tree_view_column_new_with_attributes (_("Favorites"),
436                                                         gtk_cell_renderer_text_new(),
437                                                         "text", 0, NULL);
438         
439         gtk_tree_view_append_column (GTK_TREE_VIEW(favorites), col);
440         gtk_widget_show_all (favorites);
441
442         g_object_unref (G_OBJECT(store));
443
444         return favorites;
445 }
446
447
448
449 GtkWidget*
450 modest_main_window_new (ModestConf *conf, ModestAccountMgr *account_mgr,
451                         ModestWidgetFactory *factory)
452 {
453         GObject *obj;
454         ModestMainWindowPrivate *priv;
455         
456         GtkWidget *main_vbox;
457         GtkWidget *status_hbox;
458         GtkWidget *header_win, *folder_win, *favorites_win;
459         
460         g_return_val_if_fail (factory, NULL);
461         g_return_val_if_fail (conf, NULL);
462
463         obj  = g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL);
464         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
465
466         g_object_ref (factory);
467         priv->factory = factory;
468
469         g_object_ref (conf);
470         priv->conf = conf;
471         
472         g_object_ref (account_mgr);
473         priv->account_mgr = account_mgr;
474
475         /* widgets from factory */
476         priv->folder_view = modest_widget_factory_get_folder_view (factory);
477         priv->header_view = header_view_new (MODEST_MAIN_WINDOW(obj));
478         priv->msg_preview = modest_widget_factory_get_msg_preview (factory);
479         
480         folder_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->folder_view),
481                                                  FALSE);
482         header_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->header_view),
483                                                  FALSE);                           
484         favorites_win = wrapped_in_scrolled_window (favorites_view(),FALSE);                       
485         
486         /* tool/menubar */
487         priv->menubar = menubar_new (MODEST_MAIN_WINDOW(obj));
488         priv->toolbar = GTK_WIDGET(toolbar_new (MODEST_MAIN_WINDOW(obj)));
489
490         /* paned */
491         priv->folder_paned = gtk_vpaned_new ();
492         priv->msg_paned = gtk_vpaned_new ();
493         priv->main_paned = gtk_hpaned_new ();
494         gtk_paned_add1 (GTK_PANED(priv->main_paned), priv->folder_paned);
495         gtk_paned_add2 (GTK_PANED(priv->main_paned), priv->msg_paned);
496         gtk_paned_add1 (GTK_PANED(priv->folder_paned), favorites_win);
497         gtk_paned_add2 (GTK_PANED(priv->folder_paned), folder_win);
498         gtk_paned_add1 (GTK_PANED(priv->msg_paned), header_win);
499         gtk_paned_add2 (GTK_PANED(priv->msg_paned), GTK_WIDGET(priv->msg_preview));
500
501         gtk_widget_show (GTK_WIDGET(priv->header_view));
502         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
503
504         
505         /* status bar / progress */
506         status_hbox = gtk_hbox_new (FALSE, 0);
507         gtk_box_pack_start (GTK_BOX(status_hbox),
508                             modest_widget_factory_get_folder_info_label (factory),
509                             FALSE,FALSE, 6);
510         gtk_box_pack_start (GTK_BOX(status_hbox),
511                             modest_widget_factory_get_status_bar(factory),
512                             TRUE, TRUE, 0);
513         gtk_box_pack_start (GTK_BOX(status_hbox),
514                             modest_widget_factory_get_progress_bar(factory),
515                             FALSE, FALSE, 0);
516         gtk_box_pack_start (GTK_BOX(status_hbox),
517                           modest_widget_factory_get_online_toggle(factory),
518                           FALSE, FALSE, 0);
519
520         /* putting it all together... */
521         main_vbox = gtk_vbox_new (FALSE, 6);
522         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 0);
523         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
524         gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_paned, TRUE, TRUE,0);
525         gtk_box_pack_start (GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 0);
526         
527         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
528         restore_sizes (MODEST_MAIN_WINDOW(obj));        
529
530         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
531         gtk_window_set_icon  (GTK_WINDOW(obj),
532                               modest_icon_factory_get_icon (MODEST_APP_ICON));
533         
534         gtk_widget_show_all (main_vbox);
535
536         g_signal_connect (G_OBJECT(obj), "delete-event",
537                           G_CALLBACK(on_delete_event), obj);
538         
539         return GTK_WIDGET(obj);
540 }