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