* Several fixes for the GNOME version
[modest] / src / gnome / 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 <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
34 #include <tny-error.h>
35
36 #include <widgets/modest-main-window.h>
37 #include <widgets/modest-window-priv.h>
38 #include <widgets/modest-msg-edit-window.h>
39 #include <widgets/modest-account-view-window.h>
40 #include "widgets/modest-progress-bar.h"
41
42 #include <modest-runtime.h>
43 #include "modest-widget-memory.h"
44 #include "modest-ui-actions.h"
45 #include "modest-main-window-ui.h"
46 #include "modest-main-window-ui-dimming.h"
47 #include "modest-account-mgr.h"
48 #include "modest-conf.h"
49 #include <modest-tny-msg.h>
50 #include "modest-mail-operation.h"
51 #include "modest-icon-names.h"
52
53 /* 'private'/'protected' functions */
54 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
55 static void modest_main_window_init          (ModestMainWindow *obj);
56 static void modest_main_window_finalize      (GObject *obj);
57
58 static void         restore_settings                    (ModestMainWindow *self);
59
60 static gboolean     on_header_view_button_press_event   (ModestHeaderView *header_view,
61                                                          GdkEventButton   *event,
62                                                          ModestMainWindow *self);
63
64 static gboolean     on_folder_view_button_press_event   (ModestFolderView *folder_view,
65                                                          GdkEventButton   *event,
66                                                          ModestMainWindow *self);
67
68 static gboolean     show_context_popup_menu             (ModestMainWindow *window,
69                                                          GtkTreeView      *tree_view,
70                                                          GdkEventButton   *event,
71                                                          GtkWidget        *menu);
72
73 static void         connect_signals                      (ModestMainWindow *self);
74 static void         setup_toolbar                        (ModestMainWindow *window);
75
76 static void         on_queue_changed                     (ModestMailOperationQueue *queue,
77                                                           ModestMailOperation *mail_op,
78                                                           ModestMailOperationQueueNotification type,
79                                                           ModestMainWindow *self);
80
81 static void         on_header_selected                   (ModestHeaderView *header_view, 
82                                                           TnyHeader *header,
83                                                           ModestMainWindow *main_window);
84
85 static void         save_state                           (ModestWindow *window);
86
87 /* list my signals */
88 enum {
89         /* MY_SIGNAL_1, */
90         /* MY_SIGNAL_2, */
91         LAST_SIGNAL
92 };
93
94 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
95 struct _ModestMainWindowPrivate {
96
97         GtkWidget        *folder_paned;
98         GtkWidget        *msg_paned;
99         GtkWidget        *main_paned;
100         GtkWidget        *main_vbox;
101         GtkWidget        *header_win;
102         
103         GtkWidget        *online_toggle;
104         GtkWidget        *folder_info_label;
105
106         ModestHeaderView *header_view;
107         ModestFolderView *folder_view;
108         ModestMsgView    *msg_preview;
109
110         ModestMainWindowStyle style;
111
112         GtkWidget        *status_bar;
113         GtkWidget        *progress_bar;
114
115         GSList           *progress_widgets;
116         GtkWidget        *main_bar;
117 };
118
119
120 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
121                                                 MODEST_TYPE_MAIN_WINDOW, \
122                                                 ModestMainWindowPrivate))
123
124 /* globals */
125 static GtkWindowClass *parent_class = NULL;
126
127 static const GtkActionEntry modest_folder_view_action_entries [] = {
128
129         /* Folder View CSM actions */
130         { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
131         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
132         { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL,  G_CALLBACK (modest_ui_actions_on_paste)},
133         { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
134         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
135         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
136 };
137
138 static const GtkActionEntry modest_header_view_action_entries [] = {
139
140         /* Header View CSM actions */
141         { "HeaderViewCSMOpen",          NULL,  N_("mcen_me_inbox_open"),        NULL,       NULL, G_CALLBACK (modest_ui_actions_on_open) },
142         { "HeaderViewCSMReply",         NULL,  N_("mcen_me_inbox_reply"),       NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply) },
143         { "HeaderViewCSMReplyAll",      NULL,  N_("mcen_me_inbox_replytoall"),  NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
144         { "HeaderViewCSMForward",       NULL,  N_("mcen_me_inbox_forward"),     NULL,      NULL, G_CALLBACK (modest_ui_actions_on_forward) },
145         { "HeaderViewCSMCut",           NULL,  N_("mcen_me_inbox_cut"),         "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
146         { "HeaderViewCSMCopy",          NULL,  N_("mcen_me_inbox_copy"),        "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
147         { "HeaderViewCSMPaste",         NULL,  N_("mcen_me_inbox_paste"),       "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
148         { "HeaderViewCSMDelete",        NULL,  N_("mcen_me_inbox_delete"),      NULL,      NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
149         { "HeaderViewCSMCancelSending", NULL,  N_("mcen_me_outbox_cancelsend"), NULL,      NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
150         { "HeaderViewCSMHelp",          NULL,  N_("mcen_me_inbox_help"),        NULL,      NULL, G_CALLBACK (modest_ui_actions_on_help) },
151 };
152
153 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
154         { "ToggleFolders",     MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
155 };
156
157
158 /* uncomment the following if you have defined any signals */
159 /* static guint signals[LAST_SIGNAL] = {0}; */
160
161 GType
162 modest_main_window_get_type (void)
163 {
164         static GType my_type = 0;
165         if (!my_type) {
166                 static const GTypeInfo my_info = {
167                         sizeof(ModestMainWindowClass),
168                         NULL,           /* base init */
169                         NULL,           /* base finalize */
170                         (GClassInitFunc) modest_main_window_class_init,
171                         NULL,           /* class finalize */
172                         NULL,           /* class data */
173                         sizeof(ModestMainWindow),
174                         1,              /* n_preallocs */
175                         (GInstanceInitFunc) modest_main_window_init,
176                         NULL
177                 };
178                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
179                                                   "ModestMainWindow",
180                                                   &my_info, 0);
181         }
182         return my_type;
183 }
184
185 static void
186 modest_main_window_class_init (ModestMainWindowClass *klass)
187 {
188         GObjectClass *gobject_class;
189         gobject_class = (GObjectClass*) klass;
190
191         parent_class            = g_type_class_peek_parent (klass);
192         gobject_class->finalize = modest_main_window_finalize;
193
194         ((ModestWindowClass *)(klass))->save_state_func = save_state;
195
196         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
197 }
198
199 static GtkWidget *
200 create_main_bar (GtkWidget *progress_bar)
201 {
202         GtkWidget *status_bar, *main_bar;
203
204         main_bar = gtk_hbox_new (FALSE, 6);
205
206         /* Status bar */
207         status_bar = gtk_statusbar_new ();
208         gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (status_bar), FALSE);
209
210         /* Pack */
211         gtk_box_pack_start (GTK_BOX (main_bar), status_bar, TRUE, TRUE, 0);
212         gtk_box_pack_start (GTK_BOX (main_bar), progress_bar, FALSE, FALSE, 0);
213
214         return main_bar;
215 }
216
217 static void
218 modest_main_window_init (ModestMainWindow *obj)
219 {
220         TnyAccountStore         *account_store;
221         ModestMainWindowPrivate *priv;
222         TnyFolderStoreQuery     *query;
223         GtkWidget               *icon;
224         gboolean                online;
225         GtkWidget *progress_bar;
226         
227         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
228         
229         priv->folder_paned = NULL;
230         priv->msg_paned    = NULL;
231         priv->main_paned   = NULL;      
232         priv->progress_widgets = NULL;
233
234         account_store = TNY_ACCOUNT_STORE (modest_runtime_get_account_store ());
235
236         /* online/offline toggle */
237         priv->online_toggle = gtk_toggle_button_new ();
238         online  = tny_device_is_online (modest_runtime_get_device());
239         icon    = gtk_image_new_from_icon_name (online ? GTK_STOCK_CONNECT : GTK_STOCK_DISCONNECT,
240                                                 GTK_ICON_SIZE_BUTTON);
241         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(priv->online_toggle), online);
242         gtk_button_set_image (GTK_BUTTON(priv->online_toggle),icon);
243
244         priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
245
246         /* Paned */
247         priv->folder_paned = gtk_vpaned_new ();
248         priv->main_paned = gtk_hpaned_new ();
249         priv->msg_paned = gtk_vpaned_new ();
250
251         /* Main bar */
252         priv->folder_info_label = gtk_label_new (NULL);
253         progress_bar = modest_progress_bar_new ();
254         priv->main_bar = create_main_bar (progress_bar);
255         priv->progress_widgets = g_slist_prepend (priv->progress_widgets, 
256                                                   progress_bar);
257
258         /* msg preview */
259         priv->msg_preview = MODEST_MSG_VIEW(tny_platform_factory_new_msg_view 
260                                             (modest_tny_platform_factory_get_instance ()));
261         if (!priv->msg_preview)
262                 g_printerr ("modest: cannot instantiate msgpreiew\n");
263
264         /* header view */
265         priv->header_view  =
266                 MODEST_HEADER_VIEW(modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_TWOLINES));
267         if (!priv->header_view)
268                 g_printerr ("modest: cannot instantiate header view\n");
269
270         /* folder view */
271         query = tny_folder_store_query_new ();
272         tny_folder_store_query_add_item (query, NULL,
273                                          TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
274
275         priv->folder_view = MODEST_FOLDER_VIEW (modest_folder_view_new (query));
276         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->folder_view), FALSE);
277         if (!priv->folder_view)
278                 g_printerr ("modest: cannot instantiate folder view\n");        
279         g_object_unref (G_OBJECT (query));
280 }
281
282 static void
283 modest_main_window_finalize (GObject *obj)
284 {
285         G_OBJECT_CLASS(parent_class)->finalize (obj);
286 }
287
288
289 GtkWidget*
290 modest_main_window_get_child_widget (ModestMainWindow *self,
291                                      ModestMainWindowWidgetType widget_type)
292 {
293         ModestMainWindowPrivate *priv;
294         GtkWidget *widget;
295         
296         g_return_val_if_fail (self, NULL);
297         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
298                               NULL);
299                                 
300         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
301
302         switch (widget_type) {
303         case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
304                 widget = (GtkWidget*)priv->header_view; break;
305         case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
306                 widget = (GtkWidget*)priv->folder_view; break;
307         case MODEST_MAIN_WINDOW_WIDGET_TYPE_MSG_PREVIEW:
308                 widget = (GtkWidget*)priv->msg_preview; break;
309         default:
310                 g_return_val_if_reached (NULL);
311                 return NULL;
312         }
313
314         return widget ? GTK_WIDGET(widget) : NULL;
315 }
316
317
318 static void
319 restore_settings (ModestMainWindow *self)
320 {
321         ModestConf *conf;
322         ModestMainWindowPrivate *priv;
323         ModestWindowPrivate *parent_priv;
324         
325         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
326         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
327
328         conf = modest_runtime_get_conf ();
329         
330         modest_widget_memory_restore (conf, G_OBJECT(priv->folder_paned),
331                                       MODEST_CONF_FOLDER_PANED_KEY);
332         modest_widget_memory_restore (conf, G_OBJECT(priv->msg_paned),
333                                       MODEST_CONF_MSG_PANED_KEY);
334         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
335                                       MODEST_CONF_MAIN_PANED_KEY);
336         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
337                                       MODEST_CONF_HEADER_VIEW_KEY);
338         modest_widget_memory_restore (conf, G_OBJECT(self), 
339                                       MODEST_CONF_MAIN_WINDOW_KEY);
340 }
341
342 void
343 on_online_toggle_toggled (GtkToggleButton *toggle, ModestMainWindow *self)
344 {
345         gboolean online;
346         TnyDevice *device;
347         ModestMainWindowPrivate *priv;
348
349         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
350
351         device = modest_runtime_get_device ();
352         online  = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->online_toggle));
353
354         if (online) {
355                 /* TODO: Just attempt to go online, instead of forcing the online status: */
356                 tny_device_force_online (device);
357         }
358         else
359                 tny_device_force_offline (device);
360 }
361
362 static void
363 modest_main_window_on_show (GtkWidget *widget, gpointer user_data)
364 {
365         ModestMainWindow *self = MODEST_MAIN_WINDOW (widget);
366
367         /* Connect signals */
368         connect_signals (self);
369
370         /* Restore window & widget settings */  
371         restore_settings (self);
372 }
373
374 static void
375 connect_signals (ModestMainWindow *self)
376 {       
377         ModestWindowPrivate *parent_priv;
378         ModestMainWindowPrivate *priv;
379         ModestTnyAccountStore *account_store;
380         
381         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
382         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
383
384         account_store = modest_runtime_get_account_store ();
385         
386         /* folder view */
387         g_signal_connect (G_OBJECT(priv->folder_view), "button-press-event",
388                           G_CALLBACK (on_folder_view_button_press_event),self);
389         g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
390                           G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
391         g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
392                           G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
393
394         /* header view */
395         g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
396                           G_CALLBACK(modest_ui_actions_on_header_selected), self);
397         g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
398                           G_CALLBACK(on_header_selected), self);
399         g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
400                           G_CALLBACK(modest_ui_actions_on_header_activated), self);
401         g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
402                           G_CALLBACK(modest_ui_actions_on_item_not_found), self);
403         g_signal_connect (G_OBJECT(priv->header_view), "button-press-event",
404                           G_CALLBACK (on_header_view_button_press_event), self);
405         g_signal_connect (G_OBJECT(priv->header_view),"popup-menu",
406                           G_CALLBACK (on_header_view_button_press_event), self);
407                 
408         /* msg preview */
409         g_signal_connect (G_OBJECT(priv->msg_preview), "link_clicked",
410                           G_CALLBACK(modest_ui_actions_on_msg_link_clicked), self);
411         g_signal_connect (G_OBJECT(priv->msg_preview), "link_hover",
412                           G_CALLBACK(modest_ui_actions_on_msg_link_hover), self);
413         g_signal_connect (G_OBJECT(priv->msg_preview), "attachment_clicked",
414                           G_CALLBACK(modest_ui_actions_on_msg_attachment_clicked), self);
415         g_signal_connect (G_OBJECT(priv->msg_preview), "recpt-activated",
416                           G_CALLBACK(modest_ui_actions_on_msg_recpt_activated), self);
417
418         /* Account store */
419         /* Emmitted by our TnyAccountStore::get_password_func() implementation,
420          * This is not a normal part of tinymail: */
421         g_signal_connect (G_OBJECT (modest_runtime_get_account_store()), "password_requested",
422                           G_CALLBACK (modest_ui_actions_on_password_requested), self);
423         
424         /* Device */
425         g_signal_connect (G_OBJECT(priv->online_toggle), "toggled",
426                           G_CALLBACK(on_online_toggle_toggled), self);
427
428         /* Mail Operation Queue */
429         g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
430                           "queue-changed",
431                           G_CALLBACK (on_queue_changed),
432                           self);
433 }
434
435
436 static GtkWidget*
437 wrapped_in_scrolled_window (GtkWidget *widget, gboolean needs_viewport)
438 {
439         GtkWidget *win;
440
441         win = gtk_scrolled_window_new (NULL, NULL);
442         gtk_scrolled_window_set_policy
443                 (GTK_SCROLLED_WINDOW (win),GTK_POLICY_NEVER,
444                  GTK_POLICY_AUTOMATIC);
445         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (win),
446                                              GTK_SHADOW_IN);
447         
448         if (needs_viewport)
449                 gtk_scrolled_window_add_with_viewport
450                         (GTK_SCROLLED_WINDOW(win), widget);
451         else
452                 gtk_container_add (GTK_CONTAINER(win),
453                                    widget);
454
455         return win;
456 }
457
458 static void
459 setup_toolbar (ModestMainWindow *self)
460 {
461         ModestMainWindowPrivate *priv;
462         ModestWindowPrivate *parent_priv;
463         GtkWidget *item;
464
465         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
466         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
467
468         item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
469         gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
470         item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
471         gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
472         item = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
473         gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
474
475 }
476
477
478 ModestWindow *
479 modest_main_window_new (void)
480 {
481         GObject *obj;
482         ModestMainWindow *self;
483         ModestMainWindowPrivate *priv;
484         ModestWindowPrivate *parent_priv;
485         GtkWidget *status_hbox;
486         GtkWidget *folder_win;
487         GtkWidget *preview_scroll;
488         GtkActionGroup *action_group;
489         GError *error = NULL;
490         ModestDimmingRulesGroup *menu_rules_group = NULL;
491         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
492                 
493         obj  = g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL);
494         self = MODEST_MAIN_WINDOW(obj);
495         
496         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
497         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
498
499         
500         parent_priv->ui_manager = gtk_ui_manager_new();
501         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new ();
502         action_group = gtk_action_group_new ("ModestMainWindowActions");
503         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
504
505         menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
506         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
507         
508         /* Add common actions */
509         gtk_action_group_add_actions (action_group,
510                                       modest_action_entries,
511                                       G_N_ELEMENTS (modest_action_entries),
512                                       obj);
513
514         gtk_action_group_add_actions (action_group,
515                                       modest_header_view_action_entries,
516                                       G_N_ELEMENTS (modest_header_view_action_entries),
517                                       self);
518
519         gtk_action_group_add_actions (action_group,
520                                       modest_folder_view_action_entries,
521                                       G_N_ELEMENTS (modest_folder_view_action_entries),
522                                       self);
523
524         gtk_action_group_add_toggle_actions (action_group,
525                                              modest_toggle_action_entries,
526                                              G_N_ELEMENTS (modest_toggle_action_entries),
527                                              self);
528         gtk_action_group_add_toggle_actions (action_group,
529                                              modest_main_window_toggle_action_entries,
530                                              G_N_ELEMENTS (modest_toggle_action_entries),
531                                              self);
532
533         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
534         g_object_unref (action_group);
535
536         /* Load the UI definition */
537         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
538                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
539         if (error != NULL) {
540                 g_printerr ("modest: could not merge modest-main-window-ui.xml: %s", error->message);
541                 g_error_free (error);
542                 error = NULL;
543         }
544
545         /* Add common dimming rules */
546         modest_dimming_rules_group_add_rules (menu_rules_group, 
547                                               modest_main_window_menu_dimming_entries,
548                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
549                                               MODEST_WINDOW (self));
550         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
551                                               modest_main_window_toolbar_dimming_entries,
552                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
553                                               MODEST_WINDOW (self));
554
555         /* Insert dimming rules group for this window */
556         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
557         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
558         g_object_unref (menu_rules_group);
559         g_object_unref (toolbar_rules_group);
560         
561         /* Add accelerators */
562         gtk_window_add_accel_group (GTK_WINDOW (obj), 
563                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
564
565         /* Toolbar / Menubar */
566         parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar");
567         parent_priv->menubar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar");
568
569         setup_toolbar (MODEST_MAIN_WINDOW (obj));
570         gtk_toolbar_set_tooltips (GTK_TOOLBAR (parent_priv->toolbar), TRUE);
571         folder_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->folder_view), FALSE);
572         priv->header_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->header_view), FALSE);
573
574         /* Paned */
575         preview_scroll = gtk_scrolled_window_new (NULL, NULL);
576         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (preview_scroll),
577                                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
578         gtk_paned_add1 (GTK_PANED(priv->main_paned), folder_win);
579         gtk_paned_add2 (GTK_PANED(priv->main_paned), priv->msg_paned);
580         gtk_paned_add1 (GTK_PANED(priv->msg_paned), priv->header_win);
581         gtk_container_add (GTK_CONTAINER (preview_scroll),
582                            GTK_WIDGET(priv->msg_preview));
583         gtk_paned_add2 (GTK_PANED(priv->msg_paned), preview_scroll);
584
585         /* Main Bar */
586         status_hbox = gtk_hbox_new (FALSE, 0);
587         gtk_box_pack_start (GTK_BOX(status_hbox), priv->folder_info_label, FALSE,FALSE, 6);
588         gtk_box_pack_start (GTK_BOX(status_hbox), priv->main_bar, TRUE, TRUE, 0);
589         gtk_box_pack_start (GTK_BOX(status_hbox), priv->online_toggle,FALSE, FALSE, 0);
590
591         /* putting it all together... */
592         priv->main_vbox = gtk_vbox_new (FALSE, 0);
593         gtk_box_pack_start (GTK_BOX(priv->main_vbox), parent_priv->menubar, FALSE, FALSE, 0);
594         gtk_box_pack_start (GTK_BOX(priv->main_vbox), parent_priv->toolbar, FALSE, FALSE, 0);
595         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
596         gtk_box_pack_start (GTK_BOX(priv->main_vbox), status_hbox, FALSE, FALSE, 0);
597         gtk_container_add (GTK_CONTAINER(obj), priv->main_vbox);
598
599         gtk_window_set_title (GTK_WINDOW(obj), _("Modest"));
600         gtk_window_set_icon_from_file  (GTK_WINDOW(obj), MODEST_APP_ICON, NULL);        
601         gtk_widget_show_all (priv->main_vbox);
602         
603         /* Do some tasks on show */
604         g_signal_connect (G_OBJECT(self), "show", G_CALLBACK (modest_main_window_on_show), NULL);
605
606         /* Set account store */
607         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
608                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
609
610         gtk_window_set_default_size (GTK_WINDOW (obj), 800, 600);
611
612         return (ModestWindow *) obj;
613 }
614
615 static gboolean 
616 on_header_view_button_press_event (ModestHeaderView *header_view,
617                                    GdkEventButton   *event,
618                                    ModestMainWindow *self)
619 {
620         if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
621                 GtkWidget *menu;
622                 ModestWindowPrivate *parent_priv;
623         
624                 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
625                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
626
627                 return show_context_popup_menu (self,
628                                                 GTK_TREE_VIEW (header_view), 
629                                                 event, 
630                                                 menu);
631         }
632
633         return FALSE;
634 }
635
636 static gboolean 
637 on_folder_view_button_press_event (ModestFolderView *folder_view,
638                                    GdkEventButton   *event,
639                                    ModestMainWindow *self)
640 {
641         if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
642                 GtkWidget *menu;
643                 ModestWindowPrivate *parent_priv;
644         
645                 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
646                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
647
648                 return show_context_popup_menu (self,
649                                                 GTK_TREE_VIEW (folder_view), 
650                                                 event, 
651                                                 menu);
652         }
653
654         return FALSE;
655 }
656
657 static gboolean 
658 show_context_popup_menu (ModestMainWindow *window,
659                          GtkTreeView *tree_view,
660                          GdkEventButton   *event,                        
661                          GtkWidget *menu)
662 {
663         g_return_val_if_fail (menu, FALSE);
664
665         if (event != NULL) {
666                 /* Ensure that the header is selected */
667                 GtkTreeSelection *selection;
668
669                 selection = gtk_tree_view_get_selection (tree_view);
670         
671                 if (gtk_tree_selection_count_selected_rows (selection) <= 1) {
672                         GtkTreePath *path;
673                 
674                         /* Get tree path for row that was clicked */
675                         if (gtk_tree_view_get_path_at_pos (tree_view,
676                                                            (gint) event->x, 
677                                                            (gint) event->y,
678                                                            &path, 
679                                                            NULL, NULL, NULL)) {
680                                 gtk_tree_selection_unselect_all (selection);
681                                 gtk_tree_selection_select_path (selection, path);
682                                 gtk_tree_path_free (path);
683                         }
684                 }
685
686                 /* Show popup */
687                 if (gtk_tree_selection_count_selected_rows(selection) == 1)
688                         gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
689                                         NULL, NULL,
690                                         event->button, event->time);
691         }
692         return TRUE;
693 }
694
695 static void
696 on_queue_changed (ModestMailOperationQueue *queue,
697                   ModestMailOperation *mail_op,
698                   ModestMailOperationQueueNotification type,
699                   ModestMainWindow *self)
700 {
701         GSList *tmp;
702         ModestMainWindowPrivate *priv;
703
704         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
705
706         tmp = priv->progress_widgets;
707
708         switch (type) {
709         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
710                 while (tmp) {
711                         modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
712                                                               mail_op);
713                         tmp = g_slist_next (tmp);
714                 }
715                 break;
716         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
717                 while (tmp) {
718                         modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
719                                                                  mail_op);
720                         tmp = g_slist_next (tmp);
721                 }
722                 break;
723         }
724 }
725
726 void 
727 modest_main_window_set_style (ModestMainWindow *self, 
728                               ModestMainWindowStyle style)
729 {
730         ModestMainWindowPrivate *priv;
731         ModestWindowPrivate *parent_priv;
732         GtkAction *action;
733         gboolean active;
734
735         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
736
737         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
738         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
739
740         /* no change -> nothing to do */
741         if (priv->style == style)
742                 return;
743
744        /* Get toggle button and update the state if needed. This will
745           happen only when the set_style is not invoked from the UI,
746           for example when it's called from widget memory */
747        action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
748        active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
749        if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
750            (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
751                g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
752                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
753                g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
754        }
755
756         priv->style = style;
757         switch (style) {
758         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
759                 /* Remove main paned */
760                 g_object_ref (priv->main_paned);
761                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
762
763                 /* Reparent the contents widget to the main vbox */
764                 gtk_widget_reparent (priv->header_win, priv->main_vbox);
765
766                 break;
767         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
768                 /* Remove header view */
769                 g_object_ref (priv->header_win);
770                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->header_win);
771
772                 /* Reparent the main paned */
773                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->header_win);
774                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
775
776                 break;
777         default:
778                 g_return_if_reached ();
779         }
780
781 /*      /\* Let header view grab the focus if it's being shown *\/ */
782 /*      if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) */
783 /*              gtk_widget_grab_focus (GTK_WIDGET (priv->header_view)); */
784 /*      else  */
785 /*              gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget)); */
786
787         /* Show changes */
788         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
789 }
790
791
792 ModestMainWindowStyle
793 modest_main_window_get_style (ModestMainWindow *self)
794 {
795         /* TODO */
796         return MODEST_MAIN_WINDOW_STYLE_SPLIT;
797 }
798
799 void 
800 modest_main_window_set_contents_style (ModestMainWindow *self, 
801                                        ModestMainWindowContentsStyle style)
802 {
803         /* TODO */
804 }
805
806 ModestMainWindowContentsStyle
807 modest_main_window_get_contents_style (ModestMainWindow *self)
808 {
809         /* TODO */
810         return MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS;
811 }
812
813
814 static void
815 get_msg_callback (TnyFolder *folder, 
816                   gboolean cancelled,
817                   TnyMsg *msg, 
818                   GError **err, 
819                   gpointer user_data)
820 {
821         if (!err ||!(*err)) {
822                 ModestMsgView *msg_preview;
823
824                 msg_preview = MODEST_MSG_VIEW (user_data);
825                 tny_msg_view_set_msg (TNY_MSG_VIEW (msg_preview), msg);
826         }
827
828         /* Frees */
829         g_object_unref (folder);
830 }
831
832 static void 
833 on_header_selected (ModestHeaderView *header_view, 
834                     TnyHeader *header,
835                     ModestMainWindow *main_window)
836 {
837         TnyFolder *folder;
838         ModestMainWindowPrivate *priv;
839
840         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
841
842         if (!header)
843                 return;
844
845         folder = tny_header_get_folder (header);
846
847         /* FIXME: do not use this directly. Use a mail operation
848            instead in order to get progress info */
849         tny_folder_get_msg_async (folder, 
850                                   header, 
851                                   (TnyGetMsgCallback) get_msg_callback, 
852                                   NULL, 
853                                   priv->msg_preview);
854 }
855
856 void      
857 modest_main_window_notify_send_receive_initied    (ModestMainWindow *self)
858 {
859         g_message("NOT IMPLEMENTED %s", __FUNCTION__);
860 }
861 void      
862 modest_main_window_notify_send_receive_completed    (ModestMainWindow *self)
863 {
864         g_message("NOT IMPLEMENTED %s", __FUNCTION__);
865 }
866
867 gboolean
868 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
869 {
870         g_message("NOT IMPLEMENTED %s", __FUNCTION__);
871         return FALSE;
872 }
873
874 gboolean  
875 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
876                                                    GtkTreeModel *model,
877                                                    GtkTreeRowReference *row_reference,
878                                                    ModestMainWindow *self)
879 {
880         g_message("NOT IMPLEMENTED %s", __FUNCTION__);
881         return FALSE;
882 }
883
884 gboolean  
885 modest_main_window_screen_is_on (ModestMainWindow *self)
886 {
887         g_message("NOT IMPLEMENTED %s", __FUNCTION__);
888         return TRUE;
889 }
890
891 static void
892 save_state (ModestWindow *window)
893 {
894         ModestConf *conf;
895         ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
896         ModestMainWindowPrivate *priv;
897                 
898         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
899         conf = modest_runtime_get_conf ();
900         
901         modest_widget_memory_save (conf, G_OBJECT(self), 
902                                    MODEST_CONF_MAIN_WINDOW_KEY);
903         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
904                                    MODEST_CONF_MAIN_PANED_KEY);
905         modest_widget_memory_save (conf, G_OBJECT(priv->folder_view), 
906                                    MODEST_CONF_FOLDER_VIEW_KEY);
907 }