ebd9fde3b6c03ec2af11253ca2d1bccc543facdd
[modest] / src / maemo / 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-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
40 #include <string.h>
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-maemo-utils.h>
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-mail-operation.h"
60 #include "modest-icon-names.h"
61 #include "modest-progress-bar-widget.h"
62 #include "modest-text-utils.h"
63 #include "modest-ui-dimming-manager.h"
64 #include "maemo/modest-osso-state-saving.h"
65 #include "modest-text-utils.h"
66 #include "modest-signal-mgr.h"
67
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-program.h>
70 #else
71 #include <hildon/hildon-program.h>
72 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
73
74 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
75
76 #define XALIGN 0.5
77 #define YALIGN 0.0
78 #define XSPACE 1
79 #define YSPACE 0
80
81 /* 'private'/'protected' functions */
82 static void modest_main_window_class_init  (ModestMainWindowClass *klass);
83 static void modest_main_window_init        (ModestMainWindow *obj);
84 static void modest_main_window_finalize    (GObject *obj);
85
86 static gboolean modest_main_window_window_state_event (GtkWidget *widget, 
87                                                            GdkEventWindowState *event, 
88                                                            gpointer userdata);
89
90 static void connect_signals (ModestMainWindow *self);
91
92 static void modest_main_window_disconnect_signals (ModestWindow *self);
93
94 static void restore_settings (ModestMainWindow *self, 
95                               gboolean do_folder_view_too);
96
97 static void save_state (ModestWindow *self);
98
99 static void
100 update_menus (ModestMainWindow* self);
101
102 static void modest_main_window_show_toolbar   (ModestWindow *window,
103                                                gboolean show_toolbar);
104
105 static void cancel_progressbar (GtkToolButton *toolbutton,
106                                 ModestMainWindow *self);
107
108 static void on_queue_changed   (ModestMailOperationQueue *queue,
109                                 ModestMailOperation *mail_op,
110                                 ModestMailOperationQueueNotification type,
111                                 ModestMainWindow *self);
112
113 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
114
115 static void
116 on_account_inserted (TnyAccountStore *accoust_store,
117                      TnyAccount *account,
118                      gpointer user_data);
119
120 static void
121 on_account_removed (TnyAccountStore *accoust_store,
122                     TnyAccount *account,
123                     gpointer user_data);
124
125 static void
126 on_account_changed (ModestAccountMgr* mgr,
127                     const gchar* account,
128                     gpointer user_data);
129
130 static gboolean on_inner_widgets_key_pressed  (GtkWidget *widget,
131                                                GdkEventKey *event,
132                                                gpointer user_data);
133
134 static void on_configuration_key_changed      (ModestConf* conf, 
135                                                const gchar *key, 
136                                                ModestConfEvent event,
137                                                ModestConfNotificationId id,
138                                                ModestMainWindow *self);
139
140 static void set_toolbar_mode                  (ModestMainWindow *self, 
141                                                ModestToolBarModes mode);
142
143 static gboolean set_toolbar_transfer_mode     (ModestMainWindow *self); 
144
145 static void on_show_account_action_toggled      (GtkToggleAction *action,
146                                                  gpointer user_data);
147
148 static void on_refresh_account_action_activated   (GtkAction *action,
149                                                    gpointer user_data);
150
151 static void on_send_receive_csm_activated         (GtkMenuItem *item,
152                                                    gpointer user_data);
153
154 static void
155 _on_msg_count_changed (ModestHeaderView *header_view,
156                        TnyFolder *folder,
157                        TnyFolderChange *change,
158                        ModestMainWindow *main_window);
159
160 static void
161 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
162
163
164 static GtkWidget * create_empty_view (void);
165
166 static gboolean
167 on_folder_view_focus_in (GtkWidget *widget,
168                          GdkEventFocus *event,
169                          gpointer userdata);
170 static gboolean
171 on_header_view_focus_in (GtkWidget *widget,
172                          GdkEventFocus *event,
173                          gpointer userdata);
174 static void 
175 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
176                                                 TnyFolderStore *folder_store, 
177                                                 gboolean selected,
178                                                 ModestMainWindow *main_window);
179                                                 
180 static void
181 set_at_least_one_account_visible(ModestMainWindow *self);
182
183 static void
184 modest_main_window_on_send_queue_status_changed (ModestTnySendQueue *send_queue,
185                                                  gchar *msg_id, 
186                                                  guint status,
187                                                  gpointer user_data);
188
189 /* list my signals */
190 enum {
191         /* MY_SIGNAL_1, */
192         /* MY_SIGNAL_2, */
193         LAST_SIGNAL
194 };
195
196 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
197 struct _ModestMainWindowPrivate {
198         GtkWidget *msg_paned;
199         GtkWidget *main_paned;
200         GtkWidget *main_vbox;
201         GtkWidget *contents_widget;
202         GtkWidget *empty_view;
203
204         /* Progress observers */
205         GtkWidget   *progress_bar;
206         GSList      *progress_widgets;
207
208         /* Tollbar items */
209         GtkWidget   *progress_toolitem;
210         GtkWidget   *cancel_toolitem;
211         GtkWidget   *sort_toolitem;
212         GtkWidget   *refresh_toolitem;
213         ModestToolBarModes current_toolbar_mode;
214
215         /* Merge ids used to add/remove accounts to the ViewMenu*/
216         GByteArray *merge_ids;
217         GtkActionGroup *view_additions_group;
218
219         /* On-demand widgets */
220         GtkWidget *accounts_popup;
221         GtkWidget *details_widget;
222
223         /* Optimized view enabled */
224         gboolean optimized_view;
225
226         /* Optimized view enabled */
227         gboolean send_receive_in_progress;
228
229         ModestHeaderView *header_view;
230         ModestFolderView *folder_view;
231
232         ModestMainWindowStyle style;
233         ModestMainWindowContentsStyle contents_style;
234
235         guint progress_bar_timeout;
236
237         /* Signal handler UIDs */
238         GList *queue_err_signals;
239         GSList *sighandlers;
240         
241         ModestConfNotificationId notification_id;
242 };
243 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
244                                                 MODEST_TYPE_MAIN_WINDOW, \
245                                                 ModestMainWindowPrivate))
246
247 typedef struct _GetMsgAsyncHelper {
248         ModestMainWindowPrivate *main_window_private;
249         guint action;
250         ModestTnyMsgReplyType reply_type;
251         ModestTnyMsgForwardType forward_type;
252         gchar *from;
253         TnyIterator *iter;
254 } GetMsgAsyncHelper;
255
256
257 /* globals */
258 static GtkWindowClass *parent_class = NULL;
259
260
261 /* Private actions */
262 /* This is the context sensitive menu: */
263 static const GtkActionEntry modest_folder_view_action_entries [] = {
264
265         /* Folder View CSM actions */
266         { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
267         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
268         { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL,  G_CALLBACK (modest_ui_actions_on_paste)},
269         { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
270         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
271         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
272 };
273
274 static const GtkActionEntry modest_header_view_action_entries [] = {
275
276         /* Header View CSM actions */
277         { "HeaderViewCSMOpen",          NULL,  N_("mcen_me_inbox_open"),        NULL,       NULL, G_CALLBACK (modest_ui_actions_on_open) },
278         { "HeaderViewCSMReply",         NULL,  N_("mcen_me_inbox_reply"),       NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply) },
279         { "HeaderViewCSMReplyAll",      NULL,  N_("mcen_me_inbox_replytoall"),  NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
280         { "HeaderViewCSMForward",       NULL,  N_("mcen_me_inbox_forward"),     NULL,      NULL, G_CALLBACK (modest_ui_actions_on_forward) },
281         { "HeaderViewCSMCut",           NULL,  N_("mcen_me_inbox_cut"),         "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
282         { "HeaderViewCSMCopy",          NULL,  N_("mcen_me_inbox_copy"),        "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
283         { "HeaderViewCSMPaste",         NULL,  N_("mcen_me_inbox_paste"),       "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
284         { "HeaderViewCSMDelete",        NULL,  N_("mcen_me_inbox_delete"),      NULL,      NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
285         { "HeaderViewCSMCancelSending", NULL,  N_("mcen_me_outbox_cancelsend"), NULL,      NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
286         { "HeaderViewCSMHelp",          NULL,  N_("mcen_me_inbox_help"),        NULL,      NULL, G_CALLBACK (modest_ui_actions_on_help) },
287 };
288
289 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
290         { "ToggleFolders",     MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
291 };
292
293 /************************************************************************/
294
295 GType
296 modest_main_window_get_type (void)
297 {
298         static GType my_type = 0;
299         if (!my_type) {
300                 static const GTypeInfo my_info = {
301                         sizeof(ModestMainWindowClass),
302                         NULL,           /* base init */
303                         NULL,           /* base finalize */
304                         (GClassInitFunc) modest_main_window_class_init,
305                         NULL,           /* class finalize */
306                         NULL,           /* class data */
307                         sizeof(ModestMainWindow),
308                         1,              /* n_preallocs */
309                         (GInstanceInitFunc) modest_main_window_init,
310                         NULL
311                 };
312                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
313                                                   "ModestMainWindow",
314                                                   &my_info, 0);
315         }
316         return my_type;
317 }
318
319 static void
320 modest_main_window_class_init (ModestMainWindowClass *klass)
321 {
322         GObjectClass *gobject_class;
323         gobject_class = (GObjectClass*) klass;
324         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
325
326         parent_class            = g_type_class_peek_parent (klass);
327         gobject_class->finalize = modest_main_window_finalize;
328
329         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
330         
331         modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
332         modest_window_class->save_state_func = save_state;
333         modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
334         modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
335         modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
336 }
337
338 static void
339 modest_main_window_init (ModestMainWindow *obj)
340 {
341         ModestMainWindowPrivate *priv;
342
343         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
344
345         priv->queue_err_signals = NULL;
346         priv->msg_paned    = NULL;
347         priv->main_paned   = NULL;      
348         priv->main_vbox    = NULL;
349         priv->header_view  = NULL;
350         priv->folder_view  = NULL;
351         priv->contents_widget  = NULL;
352         priv->accounts_popup  = NULL;
353         priv->details_widget  = NULL;
354         priv->empty_view  = NULL;
355         priv->progress_widgets  = NULL;
356         priv->progress_bar = NULL;
357         priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
358         priv->style  = MODEST_MAIN_WINDOW_STYLE_SPLIT;
359         priv->contents_style  = -1; /* invalid contents style. We need this to select it for the first time */
360         priv->merge_ids = NULL;
361         priv->optimized_view  = FALSE;
362         priv->send_receive_in_progress  = FALSE;
363         priv->progress_bar_timeout = 0;
364         priv->sighandlers = NULL;
365 }
366
367 static void
368 modest_main_window_finalize (GObject *obj)
369 {
370         ModestMainWindowPrivate *priv;
371
372         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
373
374         if (priv->notification_id) {
375                 modest_conf_forget_namespace (modest_runtime_get_conf (),
376                                               MODEST_CONF_NAMESPACE,
377                                               priv->notification_id);
378         }
379         
380         /* Sanity check: shouldn't be needed, the window mgr should
381            call this function before */
382         modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
383
384         modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
385
386         g_slist_free (priv->progress_widgets);
387
388         g_byte_array_free (priv->merge_ids, TRUE);
389
390         if (priv->progress_bar_timeout > 0) {
391                 g_source_remove (priv->progress_bar_timeout);
392                 priv->progress_bar_timeout = 0;
393         }
394
395         G_OBJECT_CLASS(parent_class)->finalize (obj);
396 }
397
398 GtkWidget*
399 modest_main_window_get_child_widget (ModestMainWindow *self,
400                                      ModestWidgetType widget_type)
401 {
402         ModestMainWindowPrivate *priv;
403         GtkWidget *widget;
404         
405         g_return_val_if_fail (self, NULL);
406         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
407                               NULL);
408         
409         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
410
411         switch (widget_type) {
412         case MODEST_WIDGET_TYPE_HEADER_VIEW:
413                 widget = (GtkWidget*)priv->header_view; break;
414         case MODEST_WIDGET_TYPE_FOLDER_VIEW:
415                 widget = (GtkWidget*)priv->folder_view; break;
416         default:
417                 return NULL;
418         }
419
420         return widget ? GTK_WIDGET(widget) : NULL;
421 }
422
423
424 static void
425 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
426 {
427         ModestConf *conf;
428         ModestMainWindowPrivate *priv;
429
430         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
431
432         conf = modest_runtime_get_conf ();
433
434         modest_widget_memory_restore (conf, G_OBJECT(self),
435                                       MODEST_CONF_MAIN_WINDOW_KEY);
436
437         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
438                                       MODEST_CONF_HEADER_VIEW_KEY);
439
440         if (do_folder_view_too)
441                 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
442                                       MODEST_CONF_FOLDER_VIEW_KEY);
443
444         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
445                                       MODEST_CONF_MAIN_PANED_KEY);
446
447         /* We need to force a redraw here in order to get the right
448            position of the horizontal paned separator */
449         gtk_widget_show (GTK_WIDGET (self));
450 }
451
452
453 static void
454 save_state (ModestWindow *window)
455 {
456         ModestConf *conf;
457         ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
458         ModestMainWindowPrivate *priv;
459                 
460         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
461         conf = modest_runtime_get_conf ();
462         
463         modest_widget_memory_save (conf,G_OBJECT(self), 
464                                    MODEST_CONF_MAIN_WINDOW_KEY);
465         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
466                                    MODEST_CONF_MAIN_PANED_KEY);
467         //      modest_widget_memory_save (conf, G_OBJECT(priv->header_view), 
468         //                         MODEST_CONF_HEADER_VIEW_KEY);
469         modest_widget_memory_save (conf, G_OBJECT(priv->folder_view), 
470                                    MODEST_CONF_FOLDER_VIEW_KEY);
471 }
472
473 static gint
474 compare_display_names (ModestAccountData *a,
475                        ModestAccountData *b)
476 {
477         return strcmp (a->display_name, b->display_name);
478 }
479
480 static void
481 update_menus (ModestMainWindow* self)
482 {       
483         GSList *account_names, *iter, *accounts;
484         ModestMainWindowPrivate *priv;
485         ModestWindowPrivate *parent_priv;
486         ModestAccountMgr *mgr;
487         gint i, num_accounts;
488         GList *groups;
489         gchar *default_account;
490         GtkWidget *send_receive_button, *item;
491         GtkAction *send_receive_all = NULL;
492         GSList *radio_group;
493
494         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
495         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
496
497         /* Get enabled account IDs */
498         mgr = modest_runtime_get_account_mgr ();
499         account_names = modest_account_mgr_account_names (mgr, TRUE);
500         iter = account_names;
501         accounts = NULL;
502
503         while (iter) {
504                 ModestAccountData *account_data = 
505                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
506                 accounts = g_slist_prepend (accounts, account_data);
507
508                 iter = iter->next;
509         }
510         modest_account_mgr_free_account_names (account_names);
511         account_names = NULL;
512
513         /* Order the list of accounts by its display name */
514         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
515         num_accounts = g_slist_length (accounts);
516
517         send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
518                                                       "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
519         gtk_action_set_visible (send_receive_all, num_accounts > 1);
520
521         /* Delete old send&receive popup items. We can not just do a
522            menu_detach because it does not work well with
523            tap_and_hold */
524         if (priv->accounts_popup)
525                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
526                                        (GtkCallback) gtk_widget_destroy, NULL);
527
528         /* Delete old entries in the View menu. Do not free groups, it
529            belongs to Gtk+ */
530         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
531         while (groups) {
532                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
533                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
534                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
535                                                             GTK_ACTION_GROUP (groups->data));
536                         groups = NULL;
537                         /* Remove uis */
538                         if (priv->merge_ids) {
539                                 for (i = 0; i < priv->merge_ids->len; i++)
540                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
541                                 g_byte_array_free (priv->merge_ids, TRUE);
542                         }
543                         /* We need to call this in order to ensure
544                            that the new actions are added in the right
545                            order (alphabetical */
546                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
547                 } else 
548                         groups = g_list_next (groups);
549         }
550         priv->merge_ids = g_byte_array_sized_new (num_accounts);
551
552         /* Get send receive button */
553         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
554                                                           "/ToolBar/ToolbarSendReceive");
555
556         /* Create the menu */
557         if (num_accounts > 1) {
558                 if (!priv->accounts_popup)
559                         priv->accounts_popup = gtk_menu_new ();
560                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
561                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
562                 g_signal_connect (G_OBJECT (item), 
563                                   "activate", 
564                                   G_CALLBACK (on_send_receive_csm_activated),
565                                   NULL);
566                 item = gtk_separator_menu_item_new ();
567                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
568         }
569
570         /* Create a new action group */
571         default_account = modest_account_mgr_get_default_account (mgr);
572         priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
573         radio_group = NULL;
574         for (i = 0; i < num_accounts; i++) {
575                 gchar *display_name = NULL;
576                 
577                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
578
579                 /* Create display name. The UI specification specifies a different format string 
580                  * to use for the default account, though both seem to be "%s", so 
581                  * I don't see what the point is. murrayc. */
582                 if (default_account && account_data->account_name && 
583                         !(strcmp (default_account, account_data->account_name) == 0)) {
584                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
585                                                         account_data->display_name);
586                 }
587                 else {
588                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
589                                                         account_data->display_name);
590                 }
591
592                 /* Create action and add it to the action group. The
593                    action name must be the account name, this way we
594                    could know in the handlers the account to show */
595                 if(account_data && account_data->account_name) {
596                         gchar* item_name, *refresh_action_name;
597                         guint8 merge_id = 0;
598                         GtkAction *view_account_action, *refresh_account_action;
599
600                         view_account_action = GTK_ACTION (gtk_radio_action_new (account_data->account_name,
601                                                                                 display_name, NULL, NULL, 0));
602                         gtk_action_group_add_action (priv->view_additions_group, view_account_action);
603                         gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
604                         radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
605
606                         if (default_account && account_data->account_name && 
607                             (strcmp (default_account, account_data->account_name) == 0)) {
608                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
609                         }
610
611                         /* Add ui from account data. We allow 2^9-1 account
612                            changes in a single execution because we're
613                            downcasting the guint to a guint8 in order to use a
614                            GByteArray. It should be enough. */
615                         item_name = g_strconcat (account_data->account_name, "Menu", NULL);
616                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
617                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
618                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
619                                                merge_id,
620                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
621                                                item_name,
622                                                account_data->account_name,
623                                                GTK_UI_MANAGER_MENUITEM,
624                                                FALSE);
625
626                         /* Connect the action signal "activate" */
627                         g_signal_connect_after (G_OBJECT (view_account_action),
628                                                 "toggled",
629                                                 G_CALLBACK (on_show_account_action_toggled),
630                                                 self);
631
632                         /* Create the items for the Tools->Send&Receive submenu */
633                         refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
634                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
635                                                                  display_name, NULL, NULL);
636                         printf("DEBUG: %s: menu display_name=%s\n", __FUNCTION__, display_name);
637                         gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
638
639                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
640                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
641                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
642                                                merge_id,
643                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
644                                                item_name,
645                                                refresh_action_name,
646                                                GTK_UI_MANAGER_MENUITEM,
647                                                FALSE);
648                         g_free (refresh_action_name);
649
650                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
651                                                "activate", 
652                                                G_CALLBACK (on_refresh_account_action_activated), 
653                                                g_strdup (account_data->account_name),
654                                                (GClosureNotify) g_free,
655                                                0);
656
657                         /* Create item and add it to the send&receive
658                            CSM. If there is only one account then
659                            it'll be no menu */
660                         if (priv->accounts_popup) {
661                                 GtkWidget *label = gtk_label_new(NULL);
662                                 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
663                                 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
664                                 {
665                                         gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
666                                         gtk_label_set_markup (GTK_LABEL (label), escaped);
667                                         g_free (escaped);
668                                 }
669                                 else
670                                 {
671                                         gtk_label_set_text (GTK_LABEL (label), display_name);
672                                 }
673
674                                 item = gtk_menu_item_new ();
675                                 gtk_container_add (GTK_CONTAINER (item), label);
676
677                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
678                                 g_signal_connect_data (G_OBJECT (item), 
679                                                        "activate", 
680                                                        G_CALLBACK (on_send_receive_csm_activated),
681                                                        g_strdup (account_data->account_name),
682                                                        (GClosureNotify) g_free,
683                                                        0);
684                         }
685                         g_free (item_name);
686                 }
687
688                 /* Frees */
689                 g_free (display_name);
690         }
691
692         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
693
694         /* We cannot do this in the loop above because this relies on the action
695          * group being inserted. This makes the default account appear in bold.
696          * I agree it is a rather ugly way, but I don't see another possibility. armin. */
697         for (i = 0; i < num_accounts; i++) {
698                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
699
700                 if(account_data->account_name && default_account &&
701                    strcmp (account_data->account_name, default_account) == 0) {
702                         gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
703
704                         gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
705                         GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
706                         g_free(path);
707
708                         if (item) {
709                                 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
710                                 if (GTK_IS_LABEL (child)) {
711                                         const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
712                                         gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
713                                         gtk_label_set_markup (GTK_LABEL (child), bold_name);
714                                         g_free (bold_name);
715                                 }
716                         }
717
718                         path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
719                         item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
720                         g_free (path);
721
722                         if (item) {
723                                 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
724                                 if (GTK_IS_LABEL (child)) {
725                                         const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
726                                         gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
727                                         gtk_label_set_markup (GTK_LABEL (child), bold_name);
728                                         g_free (bold_name);
729                                 }
730                         }
731
732                         g_free(item_name);
733                 }
734
735                 modest_account_mgr_free_account_data (mgr, account_data);
736         }
737
738         if (priv->accounts_popup) {
739                 /* Mandatory in order to view the menu contents */
740                 gtk_widget_show_all (priv->accounts_popup);
741
742                 /* Setup tap_and_hold just if was not done before*/
743                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
744                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
745         }
746
747         /* Frees */
748         g_slist_free (accounts);
749         g_free (default_account);
750
751
752         /* Make sure that at least one account is viewed if there are any 
753          * accounts, for instance when adding the first account: */
754         set_at_least_one_account_visible (self);
755 }
756
757 static void
758 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
759 {
760         if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
761                 gtk_scrolled_window_add_with_viewport
762                         (GTK_SCROLLED_WINDOW(win), widget);
763         else
764                 gtk_container_add (GTK_CONTAINER(win),
765                                    widget);
766 }
767
768
769 /* static gboolean */
770 /* on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self) */
771 /* { */
772 /*      modest_window_save_state (MODEST_WINDOW(self)); */
773 /*      return FALSE; */
774 /* } */
775
776 /* static void */
777 /* on_sendqueue_error_happened (TnySendQueue *self, TnyHeader *header, TnyMsg *msg, GError *err, ModestMainWindow *user_data) */
778 /* { */
779 /*      if (err) { */
780 /*              printf ("DEBUG: %s: err->code=%d, err->message=%s\n", __FUNCTION__, err->code, err->message); */
781
782 /*              if (err->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL) */
783 /*                      /\* Don't show waste the user's time by showing him a dialog telling him */
784 /*                       * that he has just cancelled something: *\/ */
785 /*                      return; */
786 /*      } */
787
788 /*      /\* Get the server name: *\/ */
789 /*      const gchar* server_name = NULL; */
790         
791 /*      TnyCamelTransportAccount* server_account = tny_camel_send_queue_get_transport_account ( */
792 /*              TNY_CAMEL_SEND_QUEUE (self)); */
793 /*      if (server_account) { */
794 /*              server_name = tny_account_get_hostname (TNY_ACCOUNT (server_account)); */
795                         
796 /*              g_object_unref (server_account); */
797 /*              server_account = NULL; */
798 /*      } */
799         
800 /*      if (!server_name) */
801 /*              server_name = _("Unknown Server");       */
802
803 /*      /\* Show the appropriate message text for the GError: *\/ */
804 /*      gchar *message = NULL; */
805 /*      if (err) { */
806 /*              switch (err->code) { */
807 /*                      case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_HOST_LOOKUP_FAILED: */
808 /*                              message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name); */
809 /*                              break; */
810 /*                      case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_SERVICE_UNAVAILABLE: */
811 /*                              message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name); */
812 /*                              break; */
813 /*                      case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_AUTHENTICATION_NOT_SUPPORTED: */
814 /*                              /\* TODO: This logical ID seems more suitable for a wrong username or password than for a  */
815 /*                               * wrong authentication method. The user is unlikely to guess at the real cause. */
816 /*                               *\/ */
817 /*                              message = g_strdup_printf (_("eemev_ni_ui_smtp_authentication_fail_error"), server_name); */
818 /*                              break; */
819 /*                      case TNY_TRANSPORT_ACCOUNT_ERROR_SEND: */
820 /*                              /\* TODO: Tinymail is still sending this sometimes when it should  */
821 /*                               * send TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL. *\/ */
822 /*                      default: */
823 /*                              message = g_strdup (_("emev_ib_ui_smtp_send_error")); */
824 /*                              break; */
825 /*              } */
826 /*      } else { */
827 /*              message = g_strdup (_("emev_ib_ui_smtp_send_error")); */
828 /*      } */
829         
830 /*      modest_maemo_show_information_note_and_forget (GTK_WINDOW (user_data), message); */
831 /*      g_free (message); */
832         
833 /*      /\* TODO: Offer to remove the message, to avoid messages in future? *\/ */
834 /*      /\* */
835 /*      TnyFolder *outbox = tny_send_queue_get_outbox (queue); */
836 /*      tny_folder_remove_msg (outbox, header, NULL); */
837 /*      tny_folder_sync (outbox, TRUE, NULL); */
838 /*      g_object_unref (outbox); */
839 /*      *\/ */
840 /* } */
841
842 typedef struct {
843         TnySendQueue *queue;
844         guint signal;
845 } QueueErrorSignal;
846
847 static void
848 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
849 {
850         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
851
852         GList *oerrsignals = priv->queue_err_signals;
853         while (oerrsignals) {
854                 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
855                 g_signal_handler_disconnect (esignal->queue, esignal->signal);
856                 g_slice_free (QueueErrorSignal, esignal);
857                 oerrsignals = g_list_next (oerrsignals);
858         }
859         g_list_free (priv->queue_err_signals);
860         priv->queue_err_signals = NULL;
861 }
862
863 /* static void */
864 /* on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self) */
865 /* { */
866 /*      ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self); */
867
868 /*      /\* When going online, do the equivalent of pressing the send/receive button,  */
869 /*       * as per the specification: */
870 /*       * (without the check for >0 accounts, though that is not specified): *\/ */
871
872 /*      TnyDevice *device = tny_account_store_get_device (store); */
873
874 /*      /\* modest_folder_view_update_model (MODEST_FOLDER_VIEW (priv->folder_view), store); *\/ */
875         
876 /*      /\* Check that we are really online. */
877 /*       * This signal should not be emitted when we are not connected,  */
878 /*       * but it seems to happen sometimes: *\/ */
879 /*       if (!tny_device_is_online (device)) */
880 /*              return; */
881                 
882 /*      const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device)); */
883 /*      printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id); */
884         
885 /*      /\* Stop the existing send queues: *\/ */
886 /*      modest_runtime_remove_all_send_queues (); */
887         
888 /*      /\* Create the send queues again, using the appropriate transport accounts  */
889 /*       * for this new connection. */
890 /*       * This could be the first time that they are created if this is the first  */
891 /*       * connection. *\/ */
892 /*      /\* TODO: Does this really destroy the TnySendQueues and their threads */
893 /*       * We do not want 2 TnySendQueues to exist with the same underlying  */
894 /*       * outbox directory. *\/ */
895
896 /*      modest_main_window_cleanup_queue_error_signals (self); */
897
898 /*      GSList *account_names = modest_account_mgr_account_names ( */
899 /*              modest_runtime_get_account_mgr(),  */
900 /*              TRUE /\* enabled accounts only *\/); */
901 /*      GSList *iter = account_names; */
902 /*      while (iter) { */
903 /*              const gchar *account_name = (const gchar*)(iter->data); */
904 /*                      if (account_name) { */
905 /*                      TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT ( */
906 /*                              modest_tny_account_store_get_transport_account_for_open_connection */
907 /*                                               (modest_runtime_get_account_store(), account_name)); */
908 /*                      if (account) { */
909 /*                              /\* Q: Is this the first location where the send-queues are requested? *\/ */
910 /*                              QueueErrorSignal *esignal = g_slice_new (QueueErrorSignal); */
911 /*                              printf ("debug: %s:\n  Transport account for %s: %s\n", __FUNCTION__, account_name,  */
912 /*                                      tny_account_get_id(TNY_ACCOUNT(account))); */
913 /*                              esignal->queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (account)); */
914 /*                              esignal->signal = g_signal_connect (G_OBJECT (esignal->queue), "error-happened", */
915 /*                                      G_CALLBACK (on_sendqueue_error_happened), self); */
916 /*                              priv->queue_err_signals = g_list_prepend (priv->queue_err_signals, esignal); */
917 /*                      } */
918 /*              } */
919                 
920 /*              iter = g_slist_next (iter); */
921 /*      } */
922
923 /*      modest_account_mgr_free_account_names (account_names); */
924 /*      account_names = NULL; */
925         
926 /*      modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self)); */
927 /* } */
928
929 static void
930 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
931 {
932         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
933
934         /* Update dimmed */     
935         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
936 }
937
938 static void
939 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
940 {
941         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
942
943         /* Update visibility */
944
945         /* Update dimmed */     
946         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
947 }
948
949 static void
950 modest_main_window_disconnect_signals (ModestWindow *self)
951 {       
952         ModestMainWindowPrivate *priv;  
953         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
954
955         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
956         priv->sighandlers = NULL;       
957 }
958
959 static void
960 connect_signals (ModestMainWindow *self)
961 {       
962         ModestWindowPrivate *parent_priv;
963         ModestMainWindowPrivate *priv;
964         GtkWidget *menu;
965         
966         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
967         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
968
969         /* folder view */
970         
971         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
972                                                        G_OBJECT(priv->folder_view), "key-press-event",
973                                                        G_CALLBACK(on_inner_widgets_key_pressed), self);
974         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder_selection_changed",
975                                                        G_CALLBACK(modest_main_window_on_folder_selection_changed), self);
976         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
977                                                        G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
978         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event", 
979                                                        G_CALLBACK (on_folder_view_focus_in), self);
980
981         /* Folder view CSM */
982         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
983         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
984         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
985                                                        G_CALLBACK(_folder_view_csm_menu_activated),
986                                                        self);
987         /* header view */
988         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
989                                                        G_CALLBACK(modest_ui_actions_on_header_selected), self);
990         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
991                                                        G_CALLBACK(modest_ui_actions_on_header_activated), self);
992         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
993                                                        G_CALLBACK(modest_ui_actions_on_item_not_found), self);
994         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
995                                                        G_CALLBACK(on_inner_widgets_key_pressed), self);
996         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
997                                                        G_CALLBACK(_on_msg_count_changed), self);
998         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
999                                                        G_CALLBACK (on_header_view_focus_in), self);
1000         
1001         /* Header view CSM */
1002         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
1003         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
1004         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
1005                                                        G_CALLBACK(_header_view_csm_menu_activated),
1006                                                        self);
1007         
1008         /* window */
1009         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
1010                           G_CALLBACK (modest_main_window_window_state_event),
1011                           NULL);
1012         
1013         /* Mail Operation Queue */
1014         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_mail_operation_queue ()),
1015                                                        "queue-changed", G_CALLBACK (on_queue_changed), self);
1016         
1017         /* Track changes in the device name */
1018         priv->notification_id =  modest_conf_listen_to_namespace (modest_runtime_get_conf (), 
1019                                                                   MODEST_CONF_NAMESPACE);
1020         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(modest_runtime_get_conf ()),
1021                                                        "key_changed", G_CALLBACK (on_configuration_key_changed), 
1022                                                        self);
1023         
1024         /* Track account changes. We need to refresh the toolbar */
1025         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store ()),
1026                                                        "account_inserted", G_CALLBACK (on_account_inserted),
1027                                                        self);
1028         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store ()),
1029                                                        "account_removed", G_CALLBACK (on_account_removed),
1030                                                        self);
1031
1032         /* We need to refresh the send & receive menu to change the bold
1033          * account when the default account changes. */
1034         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_mgr ()),
1035                                                        "account_changed", G_CALLBACK (on_account_changed),
1036                                                        self);
1037
1038         /* Account store */
1039         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store()), 
1040                                                        "password_requested",
1041                                                        G_CALLBACK (modest_ui_actions_on_password_requested), self);
1042 }
1043
1044 #if 0
1045 /** Idle handler, to send/receive at startup .*/
1046 gboolean
1047 sync_accounts_cb (ModestMainWindow *win)
1048 {
1049         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
1050         return FALSE; /* Do not call this idle handler again. */
1051 }
1052 #endif
1053
1054 static void on_hildon_program_is_topmost_notify(GObject *self,
1055         GParamSpec *propert_param, gpointer user_data)
1056 {
1057         HildonProgram *app = HILDON_PROGRAM (self);
1058         
1059         /*
1060         ModestWindow* self = MODEST_WINDOW(user_data);
1061         */
1062         
1063         /* Note that use of hildon_program_set_can_hibernate() 
1064          * is generally referred to as "setting the killable flag", 
1065          * though hibernation does not seem equal to death.
1066          * murrayc */
1067                  
1068         if (hildon_program_get_is_topmost (app)) {
1069                 /* Prevent hibernation when the progam comes to the foreground,
1070                  * because hibernation should only happen when the application 
1071                  * is in the background: */
1072                 hildon_program_set_can_hibernate (app, FALSE);
1073         } else {
1074                 /* Allow hibernation if the program has gone to the background: */
1075                 
1076                 /* However, prevent hibernation while the settings are being changed: */
1077                 const gboolean hibernation_prevented = 
1078                         modest_window_mgr_get_hibernation_is_prevented (
1079         modest_runtime_get_window_mgr ()); 
1080         
1081                 if (hibernation_prevented)
1082                         hildon_program_set_can_hibernate (app, FALSE);
1083                 else {
1084                         /* Allow hibernation, after saving the state: */
1085                         modest_osso_save_state();
1086                         hildon_program_set_can_hibernate (app, TRUE);
1087                 }
1088         }
1089         
1090 }
1091
1092 static void
1093 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1094 {
1095         GtkWidget *folder_win = (GtkWidget *) user_data;
1096         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1097         
1098         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1099         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1100 /*      wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
1101
1102         gtk_widget_show (GTK_WIDGET (priv->folder_view));
1103
1104         /* Connect signals */
1105         connect_signals ((ModestMainWindow*)self);
1106
1107         /* Set account store */
1108         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1109                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1110
1111         /* Load previous osso state, for instance if we are being restored from 
1112          * hibernation:  */
1113         modest_osso_load_state ();
1114
1115         /* Restore window & widget settings */
1116         
1117         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1118
1119         /* The UI spec wants us to show a connection dialog when the application is 
1120          * started by the user, if there is no connection.
1121          * Do this before showing the account wizard, 
1122          * because wizard needs a connection to discover capabilities. */
1123          modest_platform_connect_and_wait (GTK_WINDOW (self), NULL);
1124          
1125         /* Check if accounts exist and show the account wizard if not */
1126         gboolean accounts_exist = 
1127                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1128
1129         if (!accounts_exist) {
1130                 /* This is necessary to have the main window shown behind the dialog 
1131                 It's an ugly hack... jschmid */
1132                 gtk_widget_show_all(GTK_WIDGET(self));
1133                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1134         } else {
1135                 GSList *accounts;
1136                 GtkAction *send_receive_all;
1137                 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1138                 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1139                 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1140                                                               "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1141                 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1142                 modest_account_mgr_free_account_names (accounts);
1143         }
1144 }
1145
1146 ModestWindow *
1147 modest_main_window_new (void)
1148 {
1149         ModestMainWindow *self = NULL;  
1150         ModestMainWindowPrivate *priv = NULL;
1151         ModestWindowPrivate *parent_priv = NULL;
1152         GtkWidget *folder_win = NULL;
1153         ModestDimmingRulesGroup *menu_rules_group = NULL;
1154         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1155         GtkActionGroup *action_group = NULL;
1156         GError *error = NULL;
1157         ModestConf *conf = NULL;
1158         GtkAction *action = NULL;
1159         GdkPixbuf *window_icon;
1160         
1161         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1162         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1163         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1164
1165         parent_priv->ui_manager = gtk_ui_manager_new();
1166         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1167
1168         action_group = gtk_action_group_new ("ModestMainWindowActions");
1169         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1170
1171         menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1172         toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1173
1174         /* Add common actions */
1175         gtk_action_group_add_actions (action_group,
1176                                       modest_action_entries,
1177                                       G_N_ELEMENTS (modest_action_entries),
1178                                       self);
1179
1180         gtk_action_group_add_actions (action_group,
1181                                       modest_folder_view_action_entries,
1182                                       G_N_ELEMENTS (modest_folder_view_action_entries),
1183                                       self);
1184
1185         gtk_action_group_add_actions (action_group,
1186                                       modest_header_view_action_entries,
1187                                       G_N_ELEMENTS (modest_header_view_action_entries),
1188                                       self);
1189
1190         gtk_action_group_add_toggle_actions (action_group,
1191                                              modest_toggle_action_entries,
1192                                              G_N_ELEMENTS (modest_toggle_action_entries),
1193                                              self);
1194
1195         gtk_action_group_add_toggle_actions (action_group,
1196                                              modest_main_window_toggle_action_entries,
1197                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1198                                              self);
1199
1200         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1201         g_object_unref (action_group);
1202
1203         /* Load the UI definition */
1204         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1205                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
1206         if (error != NULL) {
1207                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1208                 g_error_free (error);
1209                 error = NULL;
1210         }
1211
1212         /* Add common dimming rules */
1213         modest_dimming_rules_group_add_rules (menu_rules_group, 
1214                                               modest_main_window_menu_dimming_entries,
1215                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1216                                               self);
1217         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1218                                               modest_main_window_toolbar_dimming_entries,
1219                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1220                                               self);
1221
1222         /* Insert dimming rules group for this window */
1223         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1224         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1225         g_object_unref (menu_rules_group);
1226         g_object_unref (toolbar_rules_group);
1227         
1228         /* Add accelerators */
1229         gtk_window_add_accel_group (GTK_WINDOW (self), 
1230                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1231
1232         /* Menubar. Update the state of some toggles */
1233         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1234         conf = modest_runtime_get_conf ();
1235         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1236                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1237         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1238                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1239         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1240                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1241         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1242                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1243         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1244         gtk_widget_show (parent_priv->menubar);
1245
1246         /* Get device name */
1247         modest_maemo_utils_get_device_name ();
1248
1249         /* header view */
1250         priv->header_view =
1251                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1252         if (!priv->header_view)
1253                 g_printerr ("modest: cannot instantiate header view\n");
1254         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1255         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1256                                       MODEST_CONF_HEADER_VIEW_KEY);
1257
1258         /* Other style properties of header view */
1259         g_object_set (G_OBJECT (priv->header_view), 
1260                       "rules-hint", FALSE,
1261                       NULL);
1262         /* gtk_widget_show (priv->header_view); */
1263
1264         /* Empty view */ 
1265         priv->empty_view = create_empty_view ();
1266         gtk_widget_show (priv->empty_view);
1267                  
1268         /* Create scrolled windows */
1269         folder_win = gtk_scrolled_window_new (NULL, NULL);
1270         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1271         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1272                                         GTK_POLICY_NEVER,
1273                                         GTK_POLICY_AUTOMATIC);
1274         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1275                                         GTK_POLICY_NEVER,
1276                                         GTK_POLICY_AUTOMATIC);
1277         /* gtk_widget_show (priv->contents_widget); */
1278
1279         /* paned */
1280         priv->main_paned = gtk_hpaned_new ();
1281         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1282         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1283         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1284
1285         /* putting it all together... */
1286         priv->main_vbox = gtk_vbox_new (FALSE, 6);
1287         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1288         gtk_widget_show (priv->main_vbox);
1289         
1290         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1291         
1292         HildonProgram *app = hildon_program_get_instance ();
1293         hildon_program_add_window (app, HILDON_WINDOW (self));
1294         
1295         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1296                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1297
1298         g_signal_connect (G_OBJECT(self), "show",
1299                           G_CALLBACK (modest_main_window_on_show), folder_win);
1300                 
1301         /* Set window icon */
1302         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1303         if (window_icon) {
1304                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1305                 g_object_unref (window_icon);
1306         }
1307
1308         /* Dont't restore settings here, 
1309          * because it requires a gtk_widget_show(), 
1310          * and we don't want to do that until later,
1311          * so that the UI is not visible for non-menu D-Bus activation.
1312          */
1313         /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1314
1315         return MODEST_WINDOW(self);
1316 }
1317
1318 gboolean 
1319 modest_main_window_close_all (ModestMainWindow *self)
1320 {
1321         GtkWidget *note;
1322         GtkResponseType response;
1323
1324         /* Create the confirmation dialog MSG-NOT308 */
1325         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
1326                                                          _("emev_nc_close_windows"),
1327                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
1328                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
1329                                                          NULL);
1330
1331         response = gtk_dialog_run (GTK_DIALOG (note));
1332         gtk_widget_destroy (GTK_WIDGET (note));
1333
1334         if (response == GTK_RESPONSE_YES)
1335                 return TRUE;
1336         else
1337                 return FALSE;
1338 }
1339
1340
1341 void 
1342 modest_main_window_set_style (ModestMainWindow *self, 
1343                               ModestMainWindowStyle style)
1344 {
1345         ModestMainWindowPrivate *priv;
1346         ModestWindowPrivate *parent_priv;
1347         GtkAction *action;
1348         gboolean active;
1349
1350         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1351
1352         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1353         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1354
1355         /* no change -> nothing to do */
1356         if (priv->style == style)
1357                 return;
1358
1359        /* Get toggle button and update the state if needed. This will
1360           happen only when the set_style is not invoked from the UI,
1361           for example when it's called from widget memory */
1362        action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1363        active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1364        if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1365            (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1366                g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1367                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1368                g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1369        }
1370
1371         priv->style = style;
1372         switch (style) {
1373         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1374                 /* Remove main paned */
1375                 g_object_ref (priv->main_paned);
1376                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1377
1378                 /* Reparent the contents widget to the main vbox */
1379                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1380
1381                 break;
1382         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1383                 /* Remove header view */
1384                 g_object_ref (priv->contents_widget);
1385                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1386
1387                 /* Reparent the main paned */
1388                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1389                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1390
1391                 break;
1392         default:
1393                 g_return_if_reached ();
1394         }
1395
1396         /* Let header view grab the focus if it's being shown */
1397         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1398                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1399         else 
1400                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1401
1402         /* Show changes */
1403         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1404 }
1405
1406 ModestMainWindowStyle
1407 modest_main_window_get_style (ModestMainWindow *self)
1408 {
1409         ModestMainWindowPrivate *priv;
1410
1411         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1412
1413         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1414         return priv->style;
1415 }
1416
1417
1418
1419 static gboolean
1420 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1421 {
1422         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1423                 ModestWindowPrivate *parent_priv;
1424                 ModestWindowMgr *mgr;
1425                 gboolean is_fullscreen;
1426                 GtkAction *fs_toggle_action;
1427                 gboolean active;
1428                 
1429                 mgr = modest_runtime_get_window_mgr ();
1430                 
1431                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1432
1433                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1434                 
1435                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1436                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1437                 if (is_fullscreen != active) {
1438                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1439                 }
1440         }
1441
1442         return FALSE;
1443
1444 }
1445
1446 static void
1447 set_homogeneous (GtkWidget *widget,
1448                  gpointer data)
1449 {
1450         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1451         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1452 }
1453
1454 static void 
1455 modest_main_window_show_toolbar (ModestWindow *self,
1456                                  gboolean show_toolbar)
1457 {
1458         ModestMainWindowPrivate *priv = NULL;
1459         ModestWindowPrivate *parent_priv = NULL;        
1460         GtkWidget *reply_button = NULL, *menu = NULL;
1461         GtkWidget *placeholder = NULL;
1462         ModestAccountMgr *mgr = NULL;
1463         TnyTransportAccount *transport_account = NULL;
1464         ModestTnySendQueue *send_queue = NULL;
1465         gint insert_index;
1466         GSList *iter = NULL;
1467         GSList *account_names = NULL;
1468         const gchar *action_name;
1469         GtkAction *action;
1470
1471         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1472         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1473         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1474
1475         /* Set optimized view status */
1476         priv->optimized_view = !show_toolbar;
1477
1478         if (!parent_priv->toolbar) {
1479                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1480                                                                   "/ToolBar");
1481                 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1482
1483                 /* Set homogeneous toolbar */
1484                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
1485                                        set_homogeneous, NULL);
1486         
1487                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1488                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1489                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1490                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1491                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1492                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1493                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1494                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1495
1496                 /* Add ProgressBar (Transfer toolbar) */ 
1497                 priv->progress_bar = modest_progress_bar_widget_new ();
1498                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1499                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1500                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1501                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1502                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1503                 
1504                 /* Connect cancel 'clicked' signal to abort progress mode */
1505                 g_signal_connect(priv->cancel_toolitem, "clicked",
1506                                  G_CALLBACK(cancel_progressbar),
1507                                  self);
1508                 
1509                 /* Add it to the observers list */
1510                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1511
1512                 /* Add to window */
1513                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1514                                            GTK_TOOLBAR (parent_priv->toolbar));
1515
1516                 /* Set reply button tap and hold menu */
1517                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1518                                                           "/ToolBar/ToolbarMessageReply");
1519                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1520                                                   "/ToolbarReplyCSM");
1521                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1522
1523                 /* Set send & receive button tap and hold menu */
1524                 update_menus (MODEST_MAIN_WINDOW (self));
1525
1526                 /* Create send queue for all defined accounts  */
1527                 mgr = modest_runtime_get_account_mgr ();
1528                 account_names = modest_account_mgr_account_names (mgr, TRUE);
1529                 iter = account_names;
1530                 while (iter) {
1531                         transport_account =
1532                                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
1533                                                       (modest_runtime_get_account_store(),
1534                                                        iter->data,
1535                                                        TNY_ACCOUNT_TYPE_TRANSPORT));
1536                         
1537                         /* Create new send queue for this new account */
1538                         send_queue =  modest_runtime_get_send_queue (transport_account);
1539                         if (MODEST_IS_TNY_SEND_QUEUE(send_queue)) {
1540                                 
1541                                 /* Connect 'status_changed' signal of this new send-queue */
1542                                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT (send_queue), "status_changed", 
1543                                                                                G_CALLBACK (modest_main_window_on_send_queue_status_changed), 
1544                                                                                self);
1545                         }
1546                         
1547                         iter = iter->next;
1548
1549                         /* free */
1550                         if (send_queue != NULL)
1551                                 g_object_unref (send_queue);
1552                         if (transport_account != NULL)
1553                                 g_object_unref (transport_account);
1554                         
1555                 }
1556                 modest_account_mgr_free_account_names (account_names);
1557         }
1558         
1559         if (show_toolbar) {
1560                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1561                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1562                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1563
1564                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1565                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1566         } else {
1567                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1568
1569         }
1570
1571         /* Update also the actions (to update the toggles in the
1572            menus), we have to do it manually because some other window
1573            of the same time could have changed it (remember that the
1574            toolbar fullscreen mode is shared by all the windows of the
1575            same type */
1576         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1577                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
1578         else
1579                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
1580
1581         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1582         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1583                                                             show_toolbar);
1584 }
1585
1586 static void
1587 modest_main_window_on_send_queue_status_changed (ModestTnySendQueue *send_queue,
1588                                                  gchar *msg_id, 
1589                                                  guint status,
1590                                                  gpointer user_data)
1591 {
1592         ModestMainWindowPrivate *priv = NULL;
1593         TnyFolderStore *selected_folder = NULL;
1594         TnyFolderType folder_type;
1595
1596         g_return_if_fail (MODEST_IS_TNY_SEND_QUEUE (send_queue));
1597         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
1598         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(user_data);
1599
1600         /* Check if selected folder is OUTBOX */
1601         selected_folder = modest_folder_view_get_selected (priv->folder_view);
1602         if (!TNY_IS_FOLDER (selected_folder)) goto frees;
1603         folder_type = modest_tny_folder_guess_folder_type (TNY_FOLDER (selected_folder)); 
1604 #if GTK_CHECK_VERSION(2, 8, 0) /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
1605         if (folder_type ==  TNY_FOLDER_TYPE_OUTBOX) {           
1606                 GtkTreeViewColumn * tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->header_view), 
1607                                                                             TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN);
1608                 gtk_tree_view_column_queue_resize (tree_column);
1609 #endif          
1610         }
1611         
1612         /* Free */
1613  frees:
1614         if (selected_folder != NULL)
1615                 g_object_unref (selected_folder);
1616 }
1617
1618 static void
1619 on_account_inserted (TnyAccountStore *accoust_store,
1620                      TnyAccount *account,
1621                      gpointer user_data)
1622 {
1623         TnyTransportAccount *transport_account = NULL;
1624         ModestTnySendQueue *send_queue = NULL;
1625         ModestMainWindowPrivate *priv;
1626         const gchar *account_name = NULL;
1627
1628         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
1629         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1630
1631         update_menus (MODEST_MAIN_WINDOW (user_data));
1632
1633         /* Get transport account */
1634         account_name = tny_account_get_name (TNY_ACCOUNT (account));
1635         transport_account =
1636                 TNY_TRANSPORT_ACCOUNT(modest_tny_account_store_get_server_account
1637                                       (modest_runtime_get_account_store(),
1638                                        account_name,
1639                                        TNY_ACCOUNT_TYPE_TRANSPORT));
1640
1641         /* Create new send queue for this new account */
1642         send_queue =  modest_runtime_get_send_queue (transport_account);
1643         if (!MODEST_IS_TNY_SEND_QUEUE(send_queue)) goto frees;
1644  
1645         /* Connect 'status_changed' signal of this new send-queue */
1646         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (send_queue), "status_changed", 
1647                                                        G_CALLBACK (modest_main_window_on_send_queue_status_changed), 
1648                                                        user_data);
1649         
1650         /* Free */
1651  frees:
1652         if (transport_account != NULL) 
1653                 g_object_unref (G_OBJECT (transport_account));
1654         if (send_queue != NULL)
1655                 g_object_unref (send_queue);
1656 }
1657
1658 static void
1659 on_account_changed (ModestAccountMgr* mgr,
1660                     const gchar* account,
1661                     gpointer user_data)
1662 {
1663         gchar *default_account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
1664
1665         /* Actually, we only want to know when another account has become
1666          * the default account, but there is no default_account_changed
1667          * signal in ModestAccountMgr. */
1668         if(strcmp(account, default_account) == 0)
1669                 update_menus (MODEST_MAIN_WINDOW (user_data));
1670
1671         g_free (default_account);
1672 }
1673
1674 static void
1675 on_account_removed (TnyAccountStore *accoust_store,
1676                      TnyAccount *account,
1677                      gpointer user_data)
1678 {
1679         update_menus (MODEST_MAIN_WINDOW (user_data));
1680 }
1681
1682 /* 
1683  * This function manages the key events used to navigate between
1684  * header and folder views (when the window is in split view)
1685  *
1686  * FROM         KEY        ACTION
1687  * -------------------------------------------------
1688  * HeaderView   GDK_Left   Move focus to folder view
1689  * FolderView   GDK_Right  Move focus to header view
1690  *
1691  * There is no need to scroll to selected row, the widgets will be the
1692  * responsibles of doing that (probably managing the focus-in event
1693  */
1694 static gboolean 
1695 on_inner_widgets_key_pressed (GtkWidget *widget,
1696                               GdkEventKey *event,
1697                               gpointer user_data)
1698 {
1699         ModestMainWindowPrivate *priv;
1700
1701         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1702
1703         /* Do nothing if we're in SIMPLE style */
1704         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1705                 return FALSE;
1706
1707         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1708                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1709         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1710                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1711
1712         return FALSE;
1713 }
1714
1715 static void
1716 set_alignment (GtkWidget *widget,
1717                gpointer data)
1718 {
1719         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1720         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1721 }
1722
1723 static GtkWidget *
1724 create_empty_view (void)
1725 {
1726         GtkLabel *label = NULL;
1727         GtkWidget *align = NULL;
1728
1729         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1730         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1731         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1732         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1733
1734         return GTK_WIDGET(align);
1735 }
1736
1737 static GtkWidget *
1738 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1739 {
1740         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1741         
1742         GtkWidget *vbox;
1743         GtkWidget *label_w;
1744         gchar *label;
1745         gchar *gray_color_markup;
1746
1747         vbox = gtk_vbox_new (FALSE, 0);
1748
1749         /* Obtain the secondary text color. We need a realized widget, that's why 
1750            we get styled_widget from outside */
1751 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1752         GdkColor color;
1753         gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1754         gray_color_markup = modest_text_utils_get_color_string (&color);
1755 #else
1756         // gray_color_markup is freed below
1757         gray_color_markup = g_strdup ("#BBBBBB");
1758 #endif  
1759         /* Account description: */
1760         
1761         if (modest_tny_account_is_virtual_local_folders (account)
1762                 || (modest_tny_account_is_memory_card_account (account))) {
1763                 gchar *tmp;
1764                 /* Local folders: */
1765         
1766                 /* Get device name */
1767                 gchar *device_name = NULL;
1768                 if (modest_tny_account_is_virtual_local_folders (account))
1769                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1770                                                       MODEST_CONF_DEVICE_NAME, NULL);
1771                 else
1772                         device_name = g_strdup (tny_account_get_name (account));
1773                                                       
1774                 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), ""); //TODO: Why the ""?
1775                 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1776                                                  gray_color_markup, tmp, device_name);
1777                 g_free (tmp);
1778                 label_w = gtk_label_new (NULL);
1779                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1780                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1781                 g_free (device_name);
1782                 g_free (label);
1783         } else {
1784                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1785                         gtk_box_pack_start (GTK_BOX (vbox), 
1786                                 gtk_label_new (tny_account_get_name (account)), 
1787                                 FALSE, FALSE, 0);
1788                 } else {
1789                         /* Other accounts, such as IMAP and POP: */
1790                         
1791                         GString *proto;
1792                         gchar *tmp;
1793         
1794                         /* Put proto in uppercase */
1795                         proto = g_string_new (tny_account_get_proto (account));
1796                         proto = g_string_ascii_up (proto);
1797                         
1798                         /* note: mcen_fi_localroot_description is something like "%s account"
1799                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1800                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1801                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1802                                                          gray_color_markup, tmp, tny_account_get_name (account));
1803                         g_free (tmp);
1804
1805                         label_w = gtk_label_new (NULL);
1806                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1807                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1808                         g_string_free (proto, TRUE);
1809                         g_free (label);
1810                 }
1811         }
1812
1813         /* Message count */
1814         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1815         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1816                                          gray_color_markup, _("mcen_fi_rootfolder_messages"), 
1817                                          modest_tny_folder_store_get_message_count (folder_store));
1818         label_w = gtk_label_new (NULL);
1819         gtk_label_set_markup (GTK_LABEL (label_w), label);
1820         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1821         g_free (label);
1822
1823         /* Folder count */
1824         label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d", 
1825                                          gray_color_markup, 
1826                                          _("mcen_fi_rootfolder_folders"), 
1827                                          modest_tny_folder_store_get_folder_count (folder_store));
1828         label_w = gtk_label_new (NULL);
1829         gtk_label_set_markup (GTK_LABEL (label_w), label);
1830         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1831         g_free (label);
1832
1833         /* Size / Date */
1834         if (modest_tny_account_is_virtual_local_folders (account)
1835                 || modest_tny_account_is_memory_card_account (account)) {
1836
1837                 gchar *size = modest_text_utils_get_display_size (
1838                         modest_tny_folder_store_get_local_size (folder_store));
1839                 
1840                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1841                                                  gray_color_markup, _("mcen_fi_rootfolder_size"),
1842                                                  size);
1843                 g_free (size);
1844                 
1845                 label_w = gtk_label_new (NULL);
1846                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1847                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1848                 g_free (label);
1849         } else if (TNY_IS_ACCOUNT(folder_store)) {
1850                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1851                 
1852                 time_t last_updated;
1853                 gchar *last_updated_string;
1854                 /* Get last updated from configuration */
1855                 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1856                                                           tny_account_get_id (account), 
1857                                                           MODEST_ACCOUNT_LAST_UPDATED, 
1858                                                           TRUE);
1859                 if (last_updated > 0) 
1860                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1861                 else
1862                         last_updated_string = g_strdup (_("mcen_va_never"));
1863
1864                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1865                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1866                 label_w = gtk_label_new (NULL);
1867                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1868                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1869                 g_free (last_updated_string);
1870                 g_free (label);
1871         }
1872
1873         g_free (gray_color_markup);
1874
1875         /* Set alignment */
1876         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1877
1878         return vbox;
1879 }
1880
1881 gboolean
1882 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1883 {
1884         ModestMainWindowPrivate *priv = NULL;
1885         
1886         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1887
1888         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1889
1890         return priv->send_receive_in_progress;
1891 }
1892
1893 void 
1894 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1895 {
1896         GtkAction *action = NULL;
1897         GtkWidget *widget = NULL;
1898         ModestMainWindowPrivate *priv = NULL;
1899                 
1900         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1901         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1902         
1903         priv->send_receive_in_progress  = TRUE;
1904
1905         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1906         gtk_action_set_sensitive (action, FALSE);
1907 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1908 /*      gtk_action_set_sensitive (action, FALSE); */
1909         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1910         gtk_widget_set_sensitive (widget, FALSE);
1911
1912
1913 void 
1914 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1915 {
1916         GtkAction *action = NULL;
1917         GtkWidget *widget = NULL;
1918         ModestMainWindowPrivate *priv = NULL;
1919                 
1920         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1921         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1922
1923         priv->send_receive_in_progress  = FALSE;
1924
1925         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1926         gtk_action_set_sensitive (action, TRUE);
1927 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1928 /*      gtk_action_set_sensitive (action, TRUE); */
1929         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1930         gtk_widget_set_sensitive (widget, TRUE);
1931
1932
1933
1934 static void
1935 _on_msg_count_changed (ModestHeaderView *header_view,
1936                        TnyFolder *folder,
1937                        TnyFolderChange *change,
1938                        ModestMainWindow *main_window)
1939 {
1940         printf ("DEBUG: %s\n", __FUNCTION__);
1941         gboolean folder_empty = FALSE;
1942         gboolean all_marked_as_deleted = FALSE;
1943         TnyFolderChangeChanged changed; 
1944         ModestMainWindowPrivate *priv;
1945         
1946         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1947         g_return_if_fail (TNY_IS_FOLDER(folder));
1948         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1949         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1950         
1951         changed = tny_folder_change_get_changed (change);
1952         
1953         /* If something changes */
1954         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1955                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);     
1956         else
1957                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1958         
1959         printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1960
1961 /*      Check header removed  (hide marked as DELETED headers) */
1962         if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1963                 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1964         }
1965
1966         /* Check if all messages are marked to be deleted */
1967         all_marked_as_deleted = modest_header_view_is_empty (header_view);
1968         folder_empty = folder_empty || all_marked_as_deleted ;
1969         
1970         /* Set contents style of headers view */
1971         if (folder_empty)  {
1972                 modest_main_window_set_contents_style (main_window,
1973                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1974                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1975         }
1976         else {
1977                 modest_main_window_set_contents_style (main_window,
1978                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1979         }       
1980 }
1981
1982
1983 void 
1984 modest_main_window_set_contents_style (ModestMainWindow *self, 
1985                                        ModestMainWindowContentsStyle style)
1986 {
1987         ModestMainWindowPrivate *priv;
1988
1989         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1990
1991         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1992
1993         /* We allow to set the same content style than the previously
1994            set if there are details, because it could happen when we're
1995            selecting different accounts consecutively */
1996         if ((priv->contents_style == style) &&
1997             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1998                 return;
1999
2000         /* Remove previous child. Delete it if it was an account
2001            details widget */
2002         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
2003         if (content) {
2004                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
2005                         g_object_ref (content);
2006                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
2007                         g_object_ref (priv->empty_view);
2008                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
2009                 }
2010                 
2011                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
2012         }
2013
2014         priv->contents_style = style;
2015
2016         switch (priv->contents_style) {
2017         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
2018                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
2019                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2020                                                       TRUE);
2021                 break;
2022         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
2023         {
2024                 /* if we're started without main win, there may not be a folder
2025                  * view. this fixes a GLib-Critical */
2026                 if (priv->folder_view) {
2027                         TnyFolderStore *selected_folderstore = 
2028                                 modest_folder_view_get_selected (priv->folder_view);
2029                         if (TNY_IS_ACCOUNT (selected_folderstore)) {    
2030                                 priv->details_widget = create_details_widget (GTK_WIDGET (self),
2031                                                                 TNY_ACCOUNT (selected_folderstore));
2032                                 
2033                                 wrap_in_scrolled_window (priv->contents_widget, 
2034                                                          priv->details_widget);
2035                         }
2036                         g_object_unref (selected_folderstore);
2037                         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2038                                                               FALSE);
2039                 }
2040                 break;
2041         }
2042         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
2043                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
2044                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2045                                                       FALSE);
2046                 break;
2047         default:
2048                 g_return_if_reached ();
2049         }
2050
2051         /* Show */
2052         gtk_widget_show_all (priv->contents_widget);
2053 }
2054
2055 ModestMainWindowContentsStyle
2056 modest_main_window_get_contents_style (ModestMainWindow *self)
2057 {
2058         ModestMainWindowPrivate *priv;
2059
2060         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
2061
2062         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2063         return priv->contents_style;
2064 }
2065
2066
2067 static void 
2068 on_configuration_key_changed (ModestConf* conf, 
2069                               const gchar *key, 
2070                               ModestConfEvent event,
2071                               ModestConfNotificationId id, 
2072                               ModestMainWindow *self)
2073 {
2074         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2075         TnyAccount *account = NULL;
2076
2077         if (!key || 
2078             priv->notification_id != id ||
2079             strcmp (key, MODEST_CONF_DEVICE_NAME))
2080                 return;
2081
2082         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
2083                 return;
2084         if (priv->folder_view) 
2085                 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
2086         if (account && TNY_IS_ACCOUNT (account) &&
2087             strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
2088                 GList *children;
2089                 GtkLabel *label;
2090                 const gchar *device_name;
2091                 gchar *new_text;
2092                 
2093                 /* Get label */
2094                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
2095                 label = GTK_LABEL (children->data);
2096                 
2097                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2098                                                       MODEST_CONF_DEVICE_NAME, NULL);
2099                 
2100                 new_text = g_strdup_printf ("%s: %s",
2101                                             _("mcen_fi_localroot_description"),
2102                                             device_name);
2103                 
2104                 gtk_label_set_text (label, new_text);
2105                 gtk_widget_show (GTK_WIDGET (label));
2106                 
2107                 g_free (new_text);
2108                 g_list_free (children);
2109         }
2110         g_object_unref (account);
2111 }
2112
2113 static gboolean
2114 set_toolbar_transfer_mode (ModestMainWindow *self)
2115 {
2116         ModestMainWindowPrivate *priv = NULL;
2117         
2118         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2119
2120         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2121
2122         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2123         
2124         if (priv->progress_bar_timeout > 0) {
2125                 g_source_remove (priv->progress_bar_timeout);
2126                 priv->progress_bar_timeout = 0;
2127         }
2128
2129         return FALSE;
2130 }
2131
2132 static void 
2133 set_toolbar_mode (ModestMainWindow *self, 
2134                   ModestToolBarModes mode)
2135 {
2136         ModestWindowPrivate *parent_priv = NULL;
2137         ModestMainWindowPrivate *priv = NULL;
2138         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2139         
2140         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2141
2142         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2143         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2144
2145         /* In case this was called before the toolbar exists: */
2146         if (!(parent_priv->toolbar))
2147                 return;
2148
2149         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
2150         
2151         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2152         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2153         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2154
2155         /* Sets current toolbar mode */
2156         priv->current_toolbar_mode = mode;
2157
2158         /* Checks the dimming rules */
2159         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2160
2161         /* Show and hide toolbar items */
2162         switch (mode) {
2163         case TOOLBAR_MODE_NORMAL:
2164                 if (sort_action)
2165                         gtk_action_set_visible (sort_action, TRUE);
2166                 if (refresh_action)
2167                         gtk_action_set_visible (refresh_action, TRUE);
2168                 if (priv->progress_toolitem) {
2169                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2170                         gtk_widget_hide (priv->progress_toolitem);
2171                 }
2172                 if (priv->progress_bar)
2173                         gtk_widget_hide (priv->progress_bar);
2174                 
2175                 if (cancel_action)
2176                         gtk_action_set_visible (cancel_action, FALSE);
2177
2178                 /* Hide toolbar if optimized view is enabled */
2179                 if (priv->optimized_view)
2180                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2181                 break;
2182         case TOOLBAR_MODE_TRANSFER:
2183                 if (sort_action)
2184                         gtk_action_set_visible (sort_action, FALSE);
2185                 if (refresh_action)
2186                         gtk_action_set_visible (refresh_action, FALSE);
2187                 if (cancel_action)
2188                         gtk_action_set_visible (cancel_action, TRUE);
2189                 if (priv->progress_toolitem) {
2190                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2191                         gtk_widget_show (priv->progress_toolitem);
2192                 }
2193                 if (priv->progress_bar)
2194                         gtk_widget_show (priv->progress_bar);
2195
2196                 /* Show toolbar if it's hiden (optimized view ) */
2197                 if (priv->optimized_view)
2198                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2199                 break;
2200         default:
2201                 g_return_if_reached ();
2202         }
2203 }
2204
2205 gboolean
2206 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2207 {
2208         ModestMainWindowPrivate *priv;
2209
2210         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2211         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2212
2213         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2214 }
2215
2216 static void
2217 cancel_progressbar (GtkToolButton *toolbutton,
2218                     ModestMainWindow *self)
2219 {
2220         GSList *tmp;
2221         ModestMainWindowPrivate *priv;
2222         
2223         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2224
2225         /* Get operation observers and cancel all the operations */
2226         tmp = priv->progress_widgets;
2227         while (tmp) {
2228                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2229                 tmp=g_slist_next(tmp);
2230         }
2231 }
2232
2233 static gboolean
2234 observers_empty (ModestMainWindow *self)
2235 {
2236         GSList *tmp = NULL;
2237         ModestMainWindowPrivate *priv;
2238         gboolean is_empty = TRUE;
2239         guint pending_ops = 0;
2240  
2241         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2242         tmp = priv->progress_widgets;
2243
2244         /* Check all observers */
2245         while (tmp && is_empty)  {
2246                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2247                 is_empty = pending_ops == 0;
2248                 
2249                 tmp = g_slist_next(tmp);
2250         }
2251         
2252         return is_empty;
2253 }
2254
2255 static void
2256 on_queue_changed (ModestMailOperationQueue *queue,
2257                   ModestMailOperation *mail_op,
2258                   ModestMailOperationQueueNotification type,
2259                   ModestMainWindow *self)
2260 {
2261         ModestMainWindowPrivate *priv;
2262         ModestMailOperationTypeOperation op_type;
2263         ModestToolBarModes mode;
2264         GSList *tmp;
2265         gboolean mode_changed = FALSE;
2266
2267         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2268         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2269                
2270         /* Get toolbar mode from operation id*/
2271         op_type = modest_mail_operation_get_type_operation (mail_op);
2272         switch (op_type) {
2273         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2274         case MODEST_MAIL_OPERATION_TYPE_OPEN:
2275                 mode = TOOLBAR_MODE_TRANSFER;
2276                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2277                         mode_changed = TRUE;
2278                 break;
2279         default:
2280                 mode = TOOLBAR_MODE_NORMAL;
2281                 
2282         }
2283                 
2284                        
2285         /* Add operation observers and change toolbar if neccessary*/
2286         tmp = priv->progress_widgets;
2287         switch (type) {
2288         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2289                 if (mode == TOOLBAR_MODE_TRANSFER) {
2290                         if (mode_changed) {
2291                                 set_toolbar_transfer_mode(self);                    
2292                         }
2293                         while (tmp) {
2294                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2295                                                                       mail_op);
2296                                 tmp = g_slist_next (tmp);
2297                         }
2298                 }
2299                 break;
2300         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2301                 /* Change toolbar mode */
2302                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
2303                         while (tmp) {
2304                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2305                                                                          mail_op);
2306                                 tmp = g_slist_next (tmp);
2307                         }
2308                         
2309                         /* If no more operations are being observed, NORMAL mode is enabled again */
2310                         if (observers_empty (self)) {
2311                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2312                         }
2313                 }
2314
2315                 break;
2316         }       
2317
2318 }
2319
2320 static void
2321 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2322 {
2323         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2324         GtkAction *action;
2325
2326         /* Get account data */
2327         ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2328         ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2329
2330         /* Set the new visible & active account */
2331         if (acc_data && acc_data->store_account) { 
2332                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2333                                                                              acc_data->store_account->account_name);
2334                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2335                 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2336                 if (action != NULL) {
2337                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2338                                 modest_maemo_toggle_action_set_active_block_notify (
2339                                         GTK_TOGGLE_ACTION (action),
2340                                         TRUE);
2341                         }
2342                 }
2343         }
2344         
2345         modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2346
2347
2348         /* Free */
2349         if (acc_data)
2350                 modest_account_mgr_free_account_data (mgr, acc_data);
2351 }
2352
2353 /* Make sure that at least one account is "viewed": */
2354 static void
2355 set_at_least_one_account_visible(ModestMainWindow *self)
2356 {
2357         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2358         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2359
2360         if (!(priv->folder_view)) {
2361                 /* It is too early to do this. */
2362                 return; 
2363         }
2364         
2365         const gchar *active_server_account_name = 
2366                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);        
2367         if (!active_server_account_name ||
2368                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2369         {
2370                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2371                 if (first_modest_name) {
2372                         set_account_visible (self, first_modest_name);
2373                         g_free (first_modest_name);
2374                 }
2375         }
2376 }
2377
2378 static void 
2379 on_show_account_action_toggled  (GtkToggleAction *action,
2380                                    gpointer user_data)
2381 {
2382         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2383
2384         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2385         if (gtk_toggle_action_get_active (action))
2386                 set_account_visible (self, acc_name);
2387 }
2388
2389 static void
2390 refresh_account (const gchar *account_name)
2391 {
2392         ModestWindow *win;
2393
2394         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2395
2396         /* If account_name == NULL, we must update all (option All) */
2397         if (!account_name)
2398                 modest_ui_actions_do_send_receive_all (win);
2399         else
2400                 modest_ui_actions_do_send_receive (account_name, win);
2401         
2402 }
2403
2404 static void 
2405 on_refresh_account_action_activated  (GtkAction *action,
2406                                       gpointer user_data)
2407 {
2408         refresh_account ((const gchar*) user_data);
2409 }
2410
2411 static void
2412 on_send_receive_csm_activated (GtkMenuItem *item,
2413                                gpointer user_data)
2414 {
2415         refresh_account ((const gchar*) user_data);
2416 }
2417
2418 static gboolean
2419 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2420 {
2421         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2422
2423         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2424         return FALSE;
2425
2426 }
2427
2428 static gboolean
2429 on_folder_view_focus_in (GtkWidget *widget,
2430                          GdkEventFocus *event,
2431                          gpointer userdata)
2432 {
2433         ModestMainWindow *main_window = NULL;
2434         
2435         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2436         main_window = MODEST_MAIN_WINDOW (userdata);
2437         
2438         /* Update toolbar dimming state */
2439         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2440
2441         return FALSE;
2442 }
2443
2444 static gboolean
2445 on_header_view_focus_in (GtkWidget *widget,
2446                          GdkEventFocus *event,
2447                          gpointer userdata)
2448 {
2449         ModestMainWindow *main_window = NULL;
2450         ModestMainWindowPrivate *priv = NULL;
2451
2452         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2453         main_window = MODEST_MAIN_WINDOW (userdata);
2454         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2455
2456         /* Update toolbar dimming state */
2457         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2458
2459         return FALSE;
2460 }
2461
2462 static void 
2463 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2464                                                 TnyFolderStore *folder_store, 
2465                                                 gboolean selected,
2466                                                 ModestMainWindow *main_window)
2467 {
2468         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2469         GtkAction *action = NULL;
2470         gboolean show_reply = TRUE;
2471         gboolean show_forward = TRUE;
2472         gboolean show_cancel_send = FALSE;
2473         gboolean show_clipboard = TRUE;
2474         gboolean show_delete = TRUE;
2475
2476         if (selected) {
2477                 if (TNY_IS_ACCOUNT (folder_store)) {
2478                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2479                 } else if (TNY_IS_FOLDER (folder_store)) {
2480                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2481                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2482                                         TNY_FOLDER (folder_store));
2483                                 switch (folder_type) {
2484                                 case TNY_FOLDER_TYPE_DRAFTS:
2485                                         show_clipboard = show_delete = TRUE;
2486                                         show_reply = show_forward = show_cancel_send = FALSE;
2487                                         break;
2488                                 case TNY_FOLDER_TYPE_SENT:
2489                                         show_forward = show_clipboard = show_delete = TRUE;
2490                                         show_reply = show_cancel_send = FALSE;
2491                                         break;
2492                                 case TNY_FOLDER_TYPE_OUTBOX:
2493                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2494                                         show_reply = show_forward = FALSE;
2495                                         break;
2496                                 default:
2497                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2498                                         show_cancel_send = FALSE;
2499                                 }
2500                         } else {
2501                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2502                                 show_cancel_send = FALSE;
2503                         }
2504                 }
2505         }
2506
2507         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2508         gtk_action_set_visible (action, show_reply);
2509         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2510         gtk_action_set_visible (action, show_reply);
2511         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2512         gtk_action_set_visible (action, show_forward);
2513         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2514         gtk_action_set_visible (action, show_cancel_send);
2515 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCut"); */
2516 /*      gtk_action_set_visible (action, show_clipboard); */
2517 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCopy"); */
2518 /*      gtk_action_set_visible (action, show_clipboard); */
2519 /*      action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMPaste"); */
2520 /*      gtk_action_set_visible (action, show_clipboard); */
2521         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2522         gtk_action_set_visible (action, show_delete);
2523
2524         /* We finally call to the ui actions handler, after updating properly
2525          * the header view CSM */
2526         modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2527
2528 }
2529
2530 gboolean 
2531 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2532                                                    GtkTreeModel *model,
2533                                                    GtkTreeRowReference *row_reference,
2534                                                    ModestMainWindow *self)
2535 {
2536         ModestMainWindowPrivate *priv = NULL;
2537         GtkTreeModel *header_model = NULL;
2538         GtkTreePath *path = NULL;
2539
2540         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2541         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2542         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2543
2544         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2545         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2546
2547         /* Do nothing if we changed the folder in the main view */
2548         if (header_model != model)
2549                 return FALSE;
2550
2551         /* Select the message in the header view */
2552         path = gtk_tree_row_reference_get_path (row_reference);
2553         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2554                                   path, NULL, FALSE);
2555         gtk_tree_path_free (path);
2556
2557         return TRUE;
2558 }
2559