* minor
[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
32 #include "modest-main-window.h"
33 #include "modest-account-view-window.h"
34 #include "modest-edit-msg-window.h"
35
36 /* 'private'/'protected' functions */
37 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
38 static void modest_main_window_init          (ModestMainWindow *obj);
39 static void modest_main_window_finalize      (GObject *obj);
40
41 static void restore_sizes (ModestMainWindow *self);
42 static void save_sizes (ModestMainWindow *self);
43
44 /* list my signals */
45 enum {
46         /* MY_SIGNAL_1, */
47         /* MY_SIGNAL_2, */
48         LAST_SIGNAL
49 };
50
51 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
52 struct _ModestMainWindowPrivate {
53
54         GtkWidget *toolbar;
55         GtkWidget *menubar;
56
57         GtkWidget *folder_paned;
58         GtkWidget *msg_paned;
59         GtkWidget *main_paned;
60         
61         ModestWidgetFactory *widget_factory;
62         ModestConf *conf;
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                 };
95                 my_type = g_type_register_static (GTK_TYPE_WINDOW,
96                                                   "ModestMainWindow",
97                                                   &my_info, 0);
98         }
99         return my_type;
100 }
101
102 static void
103 modest_main_window_class_init (ModestMainWindowClass *klass)
104 {
105         GObjectClass *gobject_class;
106         gobject_class = (GObjectClass*) klass;
107
108         parent_class            = g_type_class_peek_parent (klass);
109         gobject_class->finalize = modest_main_window_finalize;
110
111         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
112
113         /* signal definitions go here, e.g.: */
114 /*      signals[MY_SIGNAL_1] = */
115 /*              g_signal_new ("my_signal_1",....); */
116 /*      signals[MY_SIGNAL_2] = */
117 /*              g_signal_new ("my_signal_2",....); */
118 /*      etc. */
119 }
120
121 static void
122 modest_main_window_init (ModestMainWindow *obj)
123 {
124         ModestMainWindowPrivate *priv;
125
126         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
127
128         priv->widget_factory = NULL;
129 }
130
131 static void
132 modest_main_window_finalize (GObject *obj)
133 {
134         ModestMainWindowPrivate *priv;  
135         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
136         if (priv->widget_factory) {
137                 g_object_unref (G_OBJECT(priv->widget_factory));
138                 priv->widget_factory = NULL;
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
180         gtk_window_set_transient_for (GTK_WINDOW(account_win),
181                                       GTK_WINDOW(self));
182                                       
183         gtk_widget_show (account_win);
184 }
185
186
187 static void
188 on_menu_new_message (ModestMainWindow *self, guint action, GtkWidget *widget)
189 {
190         GtkWidget *msg_win;
191         ModestMainWindowPrivate *priv;
192
193
194         priv  = MODEST_MAIN_WINDOW_GET_PRIVATE(self);   
195
196         msg_win = modest_edit_msg_window_new (priv->conf,
197                                               MODEST_EDIT_TYPE_NEW,
198                                               NULL);
199         gtk_widget_show (msg_win);
200 }
201
202 static void
203 on_menu_quit (ModestMainWindow *self, guint action, GtkWidget *widget)
204 {
205         gtk_main_quit ();
206 }
207
208
209
210 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
211 static GtkItemFactoryEntry menu_items[] = {
212         { "/_File",             NULL,                   NULL,           0, "<Branch>" },
213         { "/File/_New",         "<control>N",           NULL,           0, "<StockItem>", GTK_STOCK_NEW },
214         { "/File/_Open",        "<control>O",           NULL,           0, "<StockItem>", GTK_STOCK_OPEN },
215         { "/File/_Save",        "<control>S",           NULL,           0, "<StockItem>", GTK_STOCK_SAVE },
216         { "/File/Save _As",     NULL,                   NULL,           0, "<Item>" },
217         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" },
218         { "/File/_Quit",        "<CTRL>Q",              on_menu_quit,  0, "<StockItem>", GTK_STOCK_QUIT },
219
220         { "/_Edit",             NULL,                   NULL,           0, "<Branch>" },
221         { "/Edit/_Undo",        "<CTRL>Z",              NULL,           0, "<StockItem>", GTK_STOCK_UNDO },
222         { "/Edit/_Redo",        "<shift><CTRL>Z",       NULL,           0, "<StockItem>", GTK_STOCK_REDO },
223         { "/File/sep1",         NULL,                   NULL,           0, "<Separator>" },
224         { "/Edit/Cut",          "<control>X",           NULL,           0, "<StockItem>", GTK_STOCK_CUT  },
225         { "/Edit/Copy",         "<CTRL>C",              NULL,           0, "<StockItem>", GTK_STOCK_COPY },
226         { "/Edit/Paste",        NULL,                   NULL,           0, "<StockItem>", GTK_STOCK_PASTE},
227         { "/Edit/sep1",         NULL,                   NULL,           0, "<Separator>" },
228         { "/Edit/Delete",       "<CTRL>Q",              NULL,           0, "<Item>" },
229         { "/Edit/Select all",   "<CTRL>A",              NULL,           0, "<Item>" },
230         { "/Edit/Deelect all",  "<Shift><CTRL>A",       NULL,           0, "<Item>" },
231
232         { "/_Actions",                NULL,             NULL,           0, "<Branch>" },
233         { "/Actions/_New Message",    NULL,             on_menu_new_message,            0, "<Item>" },
234         { "/Actions/_Reply",    NULL,                   NULL,           0, "<Item>" },
235         { "/Actions/_Forward",  NULL,                   NULL,           0, "<Item>" },
236         { "/Actions/_Bounce",   NULL,                   NULL,           0, "<Item>" },  
237         
238         { "/_Options",           NULL,                  NULL,           0, "<Branch>" },
239         { "/Options/_Accounts",  NULL,                  on_menu_accounts,0, "<Item>" },
240         { "/Options/_Contacts",  NULL,                  NULL,           0, "<Item>" },
241
242
243         { "/_Help",         NULL,                       NULL,           0, "<Branch>" },
244         { "/_Help/About",   NULL,                       on_menu_about,  0, "<StockItem>", GTK_STOCK_ABOUT},
245 };
246
247 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
248
249
250 static GtkWidget *
251 menubar_new (ModestMainWindow *self)
252 {
253         GtkItemFactory *item_factory;
254         GtkAccelGroup *accel_group;
255         
256         /* Make an accelerator group (shortcut keys) */
257         accel_group = gtk_accel_group_new ();
258         
259         /* Make an ItemFactory (that makes a menubar) */
260         item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
261                                              accel_group);
262         
263         /* This function generates the menu items. Pass the item factory,
264            the number of items in the array, the array itself, and any
265            callback data for the the menu items. */
266         gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, self);
267         
268         ///* Attach the new accelerator group to the window. */
269         gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
270         
271         /* Finally, return the actual menu bar created by the item factory. */
272         return gtk_item_factory_get_widget (item_factory, "<main>");
273 }
274
275
276
277
278 static ModestHeaderView*
279 header_view_new (ModestMainWindow *self)
280 {
281         int i;
282         GSList *columns = NULL;
283         ModestHeaderView *header_view;
284         ModestMainWindowPrivate *priv;
285         ModestHeaderViewColumn cols[] = {
286                 MODEST_HEADER_VIEW_COLUMN_MSGTYPE,
287                 MODEST_HEADER_VIEW_COLUMN_ATTACH,
288                 MODEST_HEADER_VIEW_COLUMN_FROM,
289                 MODEST_HEADER_VIEW_COLUMN_SUBJECT,
290                 MODEST_HEADER_VIEW_COLUMN_RECEIVED_DATE
291         };
292
293         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
294         
295         for (i = 0 ; i != sizeof(cols) / sizeof(ModestHeaderViewColumn); ++i)
296                 columns = g_slist_append (columns, GINT_TO_POINTER(cols[i]));
297
298         header_view = modest_widget_factory_get_header_view (priv->widget_factory);
299         modest_header_view_set_columns (header_view, columns);
300         g_slist_free (columns);
301
302         return header_view;
303 }
304
305
306 static void
307 restore_sizes (ModestMainWindow *self)
308 {
309         ModestMainWindowPrivate *priv;
310         
311         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
312         
313         modest_widget_memory_restore_settings (priv->conf,GTK_WIDGET(self),
314                                                "modest-main-window");
315         modest_widget_memory_restore_settings (priv->conf, GTK_WIDGET(priv->folder_paned),
316                                                "modest-folder-paned");
317         modest_widget_memory_restore_settings (priv->conf, GTK_WIDGET(priv->msg_paned),
318                                                "modest-msg-paned");
319         modest_widget_memory_restore_settings (priv->conf, GTK_WIDGET(priv->main_paned),
320                                                "modest-main-paned");
321
322 }
323
324
325 static void
326 save_sizes (ModestMainWindow *self)
327 {
328         ModestMainWindowPrivate *priv;
329         
330         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
331         
332         modest_widget_memory_save_settings (priv->conf,GTK_WIDGET(self),
333                                             "modest-main-window");
334         modest_widget_memory_save_settings (priv->conf, GTK_WIDGET(priv->folder_paned),
335                                             "modest-folder-paned");
336         modest_widget_memory_save_settings (priv->conf, GTK_WIDGET(priv->msg_paned),
337                                             "modest-msg-paned");
338         modest_widget_memory_save_settings (priv->conf, GTK_WIDGET(priv->main_paned),
339                                             "modest-main-paned");
340
341         
342
343 }
344
345
346 static GtkWidget*
347 wrapped_in_scrolled_window (GtkWidget *widget, gboolean needs_viewport)
348 {
349         GtkWidget *win;
350
351         win = gtk_scrolled_window_new (NULL, NULL);
352         gtk_scrolled_window_set_policy
353                 (GTK_SCROLLED_WINDOW (win),GTK_POLICY_NEVER,
354                  GTK_POLICY_AUTOMATIC);
355         
356         if (needs_viewport)
357                 gtk_scrolled_window_add_with_viewport
358                         (GTK_SCROLLED_WINDOW(win), widget);
359         else
360                 gtk_container_add (GTK_CONTAINER(win),
361                                    widget);
362
363         return win;
364 }
365
366
367 static gboolean
368 on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self)
369 {
370         save_sizes (self);
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, 5);
427         gtk_box_pack_start (GTK_BOX(status_hbox),
428                             modest_widget_factory_get_status_bar(factory),
429                             FALSE, TRUE, 5);
430         gtk_box_pack_start (GTK_BOX(status_hbox),
431                             modest_widget_factory_get_progress_bar(factory),
432                             FALSE, TRUE, 5);
433         
434         /* putting it all together... */
435         main_vbox = gtk_vbox_new (FALSE, 2);
436         gtk_box_pack_start (GTK_BOX(main_vbox), priv->menubar, FALSE, FALSE, 2);
437         gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, TRUE, 5);
438         gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_paned, TRUE, TRUE, 2);
439         gtk_box_pack_start (GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 5);
440         
441         gtk_container_add (GTK_CONTAINER(obj), main_vbox);
442         gtk_widget_show_all (main_vbox);
443         
444         gtk_window_set_title (GTK_WINDOW(obj), "Modest");
445
446         g_signal_connect (G_OBJECT(obj), "delete-event",
447                           G_CALLBACK(on_delete_event), obj);
448
449         restore_sizes (MODEST_MAIN_WINDOW(obj));        
450         
451         return GTK_WIDGET(obj);
452 }