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