16bc5a7b4e69d0e017a39f18b528ba2b4fc04fa6
[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         ModestHeaderView *header_view;
59         ModestFolderView *folder_view;
60         ModestMsgView    *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
170         g_return_if_fail (widget);
171         g_return_if_fail (self);
172         
173         priv        = MODEST_MAIN_WINDOW_GET_PRIVATE(self);     
174         account_win = modest_account_view_window_new (priv->conf,
175                                                       priv->widget_factory);
176         gtk_widget_show (account_win);
177 }
178
179
180 static void
181 on_menu_new_message (ModestMainWindow *self, guint action, GtkWidget *widget)
182 {
183         GtkWidget *msg_win;
184
185         msg_win = modest_msg_window_new (MODEST_MSG_WINDOW_TYPE_NEW,
186                                          NULL);
187
188         gtk_widget_show (msg_win);
189 }
190
191
192
193 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
194 static GtkItemFactoryEntry menu_items[] = {
195         { "/_File",             NULL,                   NULL,           0, "<Branch>" },
196         { "/File/_New",         "<control>N",           NULL,           0, "<StockItem>", GTK_STOCK_NEW },
197         { "/File/_Open",        "<control>O",           NULL,           0, "<StockItem>", GTK_STOCK_OPEN },
198         { "/File/_Save",        "<control>S",           NULL,           0, "<StockItem>", GTK_STOCK_SAVE },
199         { "/File/Save _As",     NULL,                   NULL,           0, "<Item>" },
200         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" },
201         { "/File/_Quit",        "<CTRL>Q",              gtk_main_quit,  0, "<StockItem>", GTK_STOCK_QUIT },
202
203         { "/_Edit",             NULL,                   NULL,           0, "<Branch>" },
204         { "/Edit/_Undo",        "<CTRL>Z",              NULL,           0, "<StockItem>", GTK_STOCK_UNDO },
205         { "/Edit/_Redo",        "<shift><CTRL>Z",       NULL,           0, "<StockItem>", GTK_STOCK_REDO },
206         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" },
207         { "/Edit/Cut",          "<control>X",           NULL,           0, "<StockItem>", GTK_STOCK_CUT  },
208         { "/Edit/Copy",         "<CTRL>C",              NULL,           0, "<StockItem>", GTK_STOCK_COPY },
209         { "/Edit/Paste",        NULL,                   NULL,           0, "<StockItem>", GTK_STOCK_PASTE},
210         { "/Edit/sep1",         NULL,                   NULL,           0, "<Separator>" },
211         { "/Edit/Delete",       "<CTRL>Q",              NULL,           0, "<Item>" },
212         { "/Edit/Select all",   "<CTRL>A",              NULL,           0, "<Item>" },
213         { "/Edit/Deelect all",  "<Shift><CTRL>A",       NULL,           0, "<Item>" },
214
215         { "/_Actions",                NULL,             NULL,           0, "<Branch>" },
216         { "/Actions/_New Message",    NULL,             on_menu_new_message,            0, "<Item>" },
217         { "/Actions/_Reply",    NULL,                   NULL,           0, "<Item>" },
218         { "/Actions/_Forward",  NULL,                   NULL,           0, "<Item>" },
219         { "/Actions/_Bounce",   NULL,                   NULL,           0, "<Item>" },  
220         
221         { "/_Options",           NULL,                  NULL,           0, "<Branch>" },
222         { "/Options/_Accounts",  NULL,                  on_menu_accounts,0, "<Item>" },
223         { "/Options/_Contacts",  NULL,                  NULL,           0, "<Item>" },
224
225
226         { "/_Help",         NULL,                       NULL,           0, "<Branch>" },
227         { "/_Help/About",   NULL,                       on_menu_about,  0, "<StockItem>", GTK_STOCK_ABOUT},
228 };
229
230 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
231
232
233 static GtkWidget *
234 menubar_new (ModestMainWindow *self)
235 {
236         GtkItemFactory *item_factory;
237         GtkAccelGroup *accel_group;
238         
239         /* Make an accelerator group (shortcut keys) */
240         accel_group = gtk_accel_group_new ();
241         
242         /* Make an ItemFactory (that makes a menubar) */
243         item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
244                                              accel_group);
245         
246         /* This function generates the menu items. Pass the item factory,
247            the number of items in the array, the array itself, and any
248            callback data for the the menu items. */
249         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, self);
250         
251         ///* Attach the new accelerator group to the window. */
252         gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
253         
254         /* Finally, return the actual menu bar created by the item factory. */
255         return gtk_item_factory_get_widget (item_factory, "<main>");
256 }
257
258
259
260
261 static ModestHeaderView*
262 header_view_new (ModestMainWindow *self)
263 {
264         int i;
265         GSList *columns = NULL;
266         ModestHeaderView *header_view;
267         ModestMainWindowPrivate *priv;
268         ModestHeaderViewColumn cols[] = {
269                 MODEST_HEADER_VIEW_COLUMN_MSGTYPE,
270                 MODEST_HEADER_VIEW_COLUMN_ATTACH,
271                 MODEST_HEADER_VIEW_COLUMN_FROM,
272                 MODEST_HEADER_VIEW_COLUMN_SUBJECT,
273                 MODEST_HEADER_VIEW_COLUMN_RECEIVED_DATE
274         };
275
276         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
277         
278         for (i = 0 ; i != sizeof(cols) / sizeof(ModestHeaderViewColumn); ++i)
279                 columns = g_slist_append (columns, GINT_TO_POINTER(cols[i]));
280
281         header_view = modest_widget_factory_get_header_view (priv->widget_factory);
282         modest_header_view_set_columns (header_view, columns);
283         g_slist_free (columns);
284
285         return header_view;
286 }
287
288
289 static void
290 set_sizes (ModestMainWindow *self)
291 {
292         ModestMainWindowPrivate *priv;
293
294         int win_x,win_y;
295         int fol_x,fol_pos;
296         int msg_x,msg_pos;
297         
298         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
299
300         /* size of the whole window */
301         win_x = modest_conf_get_int_or_default (priv->conf,
302                                                       MODEST_MAIN_WINDOW_WIDTH,
303                                                       MODEST_MAIN_WINDOW_WIDTH_DEFAULT);
304         win_y = modest_conf_get_int_or_default (priv->conf,
305                                                       MODEST_MAIN_WINDOW_HEIGHT,
306                                                       MODEST_MAIN_WINDOW_HEIGHT_DEFAULT);
307         gtk_window_set_default_size (GTK_WINDOW(self), win_x, win_y);
308         
309         /* size of the folder pane */
310         fol_x = modest_conf_get_int_or_default (priv->conf,
311                                                       MODEST_FOLDER_PANED_WIDTH,
312                                                       MODEST_FOLDER_PANED_WIDTH_DEFAULT);
313         fol_pos = modest_conf_get_int_or_default (priv->conf,
314                                                         MODEST_FOLDER_PANED_DIVIDER_POS,
315                                                         MODEST_FOLDER_PANED_DIVIDER_POS_DEFAULT);
316         if (1 > fol_x || fol_x > win_x || 1 > fol_pos || fol_pos > win_y) {
317                 g_printerr ("modest: folder paned <x,pos> out of range: <%d,%d>\n",
318                             fol_x, fol_pos);
319         } else {
320                 /* slightly off... */
321                 gtk_widget_set_size_request (priv->folder_paned, fol_x, win_y);
322                 gtk_paned_set_position (GTK_PANED(priv->folder_paned),
323                                         fol_pos);
324         }
325         
326         /* size of the folder pane */
327         msg_x = modest_conf_get_int_or_default (priv->conf,
328                                                       MODEST_MSG_PANED_WIDTH,
329                                                       MODEST_MSG_PANED_WIDTH_DEFAULT);
330         msg_pos = modest_conf_get_int_or_default (priv->conf,
331                                                         MODEST_MSG_PANED_DIVIDER_POS,
332                                                         MODEST_MSG_PANED_DIVIDER_POS_DEFAULT);
333         if (1 > msg_x || msg_x > win_x || 1 > msg_pos || msg_pos > win_y) {
334                 g_printerr ("modest: msg paned <x,pos> out of range: <%d,%d>\n",
335                             msg_x, msg_pos);
336         } else {
337                 /* slightly off... */
338                 gtk_widget_set_size_request (priv->msg_paned,
339                                              fol_x, win_y);
340                 gtk_paned_set_position (GTK_PANED(priv->msg_paned),
341                                         msg_pos);
342         }
343 }
344
345
346
347 static GtkWidget*
348 wrapped_in_scrolled_window (GtkWidget *widget, gboolean needs_viewport)
349 {
350         GtkWidget *win;
351
352         win = gtk_scrolled_window_new (NULL, NULL);
353         gtk_scrolled_window_set_policy
354                 (GTK_SCROLLED_WINDOW (win),GTK_POLICY_NEVER,
355                  GTK_POLICY_AUTOMATIC);
356         
357         if (needs_viewport)
358                 gtk_scrolled_window_add_with_viewport
359                         (GTK_SCROLLED_WINDOW(win), widget);
360         else
361                 gtk_container_add (GTK_CONTAINER(win),
362                                    widget);
363
364         return win;
365 }
366
367 GtkWidget*
368 modest_main_window_new (ModestWidgetFactory *factory, ModestConf *conf)
369 {
370         GObject *obj;
371         ModestMainWindowPrivate *priv;
372         
373         GtkWidget *main_vbox;
374         GtkWidget *main_paned;
375         GtkWidget *status_hbox;
376         GtkWidget *header_win, *folder_win; 
377         
378         g_return_val_if_fail (factory, NULL);
379         g_return_val_if_fail (conf, NULL);
380
381         obj  = g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL);
382         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
383
384         g_object_ref (factory);
385         priv->widget_factory = factory;
386
387         g_object_ref (conf);
388         priv->conf = conf;
389
390         /* widgets from factory */
391         priv->folder_view = modest_widget_factory_get_folder_view (factory);
392         priv->header_view = header_view_new (MODEST_MAIN_WINDOW(obj));
393         priv->msg_preview = modest_widget_factory_get_msg_preview (factory);
394
395         folder_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->folder_view),
396                                                  FALSE);
397         header_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->header_view),
398                                                  FALSE);                           
399         /* tool/menubar */
400         priv->menubar = menubar_new (MODEST_MAIN_WINDOW(obj));
401         priv->toolbar = gtk_toolbar_new ();
402
403         /* paned */
404         priv->folder_paned = gtk_vpaned_new ();
405         priv->msg_paned = gtk_vpaned_new ();
406         main_paned = gtk_hpaned_new ();
407         gtk_paned_add1 (GTK_PANED(main_paned), priv->folder_paned);
408         gtk_paned_add2 (GTK_PANED(main_paned), priv->msg_paned);
409         gtk_paned_add1 (GTK_PANED(priv->folder_paned),
410                         gtk_label_new (_("Favorites")));
411         gtk_paned_add2 (GTK_PANED(priv->folder_paned), folder_win);
412         gtk_paned_add1 (GTK_PANED(priv->msg_paned), header_win);
413         gtk_paned_add2 (GTK_PANED(priv->msg_paned), GTK_WIDGET(priv->msg_preview));
414
415         gtk_widget_show (GTK_WIDGET(priv->header_view));
416                 
417         /* status bar / progress */
418         priv->status_bar   = gtk_statusbar_new ();
419         priv->progress_bar = gtk_progress_bar_new ();
420         status_hbox = gtk_hbox_new (TRUE, 5);
421         gtk_box_pack_start (GTK_BOX(status_hbox), priv->progress_bar, FALSE, TRUE, 5);
422         gtk_box_pack_start (GTK_BOX(status_hbox), priv->status_bar, FALSE, TRUE, 5);
423         
424         /* putting it all together... */
425         main_vbox = gtk_vbox_new (FALSE, 2);
426         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 2);
427         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, TRUE, 5);
428         gtk_box_pack_start (GTK_BOX(main_vbox), main_paned, TRUE, TRUE, 2);
429         gtk_box_pack_start (GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 5);
430         
431         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
432         gtk_widget_show_all (main_vbox);
433         
434         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
435
436         set_sizes (MODEST_MAIN_WINDOW(obj));    
437         return GTK_WIDGET(obj);
438 }