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