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