1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
35 #include <tny-iterator.h>
36 #include <tny-error.h>
37 #include "modest-hildon-includes.h"
38 #include "modest-defs.h"
40 #include "widgets/modest-header-view-priv.h"
41 #include "widgets/modest-main-window.h"
42 #include "widgets/modest-msg-edit-window.h"
43 #include "widgets/modest-account-view-window.h"
44 #include "modest-runtime.h"
45 #include "modest-account-mgr-helpers.h"
46 #include "modest-platform.h"
47 #include "modest-widget-memory.h"
48 #include "modest-window-priv.h"
49 #include "modest-main-window-ui.h"
50 #include "modest-main-window-ui-dimming.h"
51 #include "modest-account-mgr.h"
52 #include "modest-tny-account.h"
53 #include "modest-tny-folder.h"
54 #include "modest-conf.h"
55 #include <modest-utils.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.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"
68 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
75 /* 'private'/'protected' functions */
76 static void modest_main_window_class_init (ModestMainWindowClass *klass);
77 static void modest_main_window_init (ModestMainWindow *obj);
78 static void modest_main_window_finalize (GObject *obj);
80 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
81 GdkEventWindowState *event,
84 static void connect_signals (ModestMainWindow *self);
86 static void modest_main_window_disconnect_signals (ModestWindow *self);
88 static void restore_settings (ModestMainWindow *self,
89 gboolean do_folder_view_too);
91 static void save_state (ModestWindow *self);
93 static void update_menus (ModestMainWindow* self);
95 static void modest_main_window_show_toolbar (ModestWindow *window,
96 gboolean show_toolbar);
98 static void cancel_progressbar (GtkToolButton *toolbutton,
99 ModestMainWindow *self);
101 static void on_queue_changed (ModestMailOperationQueue *queue,
102 ModestMailOperation *mail_op,
103 ModestMailOperationQueueNotification type,
104 ModestMainWindow *self);
106 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
108 static void on_account_inserted (TnyAccountStore *accoust_store,
112 static void on_account_removed (TnyAccountStore *accoust_store,
116 static void on_account_changed (TnyAccountStore *account_store,
120 static void on_default_account_changed (ModestAccountMgr* mgr,
123 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
127 static void on_configuration_key_changed (ModestConf* conf,
129 ModestConfEvent event,
130 ModestConfNotificationId id,
131 ModestMainWindow *self);
133 static void set_toolbar_mode (ModestMainWindow *self,
134 ModestToolBarModes mode);
136 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
138 static void on_show_account_action_toggled (GtkToggleAction *action,
141 static void on_refresh_account_action_activated (GtkAction *action,
144 static void on_send_receive_csm_activated (GtkMenuItem *item,
147 static void on_msg_count_changed (ModestHeaderView *header_view,
149 TnyFolderChange *change,
150 ModestMainWindow *main_window);
152 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
155 static GtkWidget * create_empty_view (void);
157 static gboolean on_folder_view_focus_in (GtkWidget *widget,
158 GdkEventFocus *event,
161 static gboolean on_header_view_focus_in (GtkWidget *widget,
162 GdkEventFocus *event,
165 static void on_folder_selection_changed (ModestFolderView *folder_view,
166 TnyFolderStore *folder_store,
168 ModestMainWindow *main_window);
170 static void set_at_least_one_account_visible(ModestMainWindow *self);
172 static void on_updating_msg_list (ModestHeaderView *header_view,
176 static gboolean restore_paned_timeout_handler (gpointer *data);
178 static gboolean show_opening_banner (gpointer user_data);
180 static void on_window_destroy (GtkObject *widget,
183 static void on_window_hide (GObject *gobject,
187 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
188 struct _ModestMainWindowPrivate {
189 GtkWidget *msg_paned;
190 GtkWidget *main_paned;
191 GtkWidget *main_vbox;
192 GtkWidget *contents_widget;
193 GtkWidget *empty_view;
195 /* Progress observers */
196 GtkWidget *progress_bar;
197 GSList *progress_widgets;
200 GtkWidget *progress_toolitem;
201 GtkWidget *cancel_toolitem;
202 GtkWidget *sort_toolitem;
203 GtkWidget *refresh_toolitem;
204 ModestToolBarModes current_toolbar_mode;
206 /* Merge ids used to add/remove accounts to the ViewMenu*/
207 GByteArray *merge_ids;
208 GtkActionGroup *view_additions_group;
210 /* On-demand widgets */
211 GtkWidget *accounts_popup;
212 GtkWidget *details_widget;
214 /* Optimized view enabled */
215 gboolean optimized_view;
217 /* Optimized view enabled */
218 gboolean send_receive_in_progress;
220 ModestHeaderView *header_view;
221 ModestFolderView *folder_view;
223 ModestMainWindowStyle style;
224 ModestMainWindowContentsStyle contents_style;
225 gboolean wait_for_settings;
227 guint progress_bar_timeout;
228 guint restore_paned_timeout;
230 /* Signal handler UIDs */
231 GList *queue_err_signals;
234 /* "Updating" banner for header view */
235 GtkWidget *updating_banner;
236 guint updating_banner_timeout;
238 /* "Opening" banner for header view */
239 GtkWidget *opening_banner;
240 guint opening_banner_timeout;
243 osso_display_state_t display_state;
245 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
246 MODEST_TYPE_MAIN_WINDOW, \
247 ModestMainWindowPrivate))
249 typedef struct _GetMsgAsyncHelper {
250 ModestMainWindowPrivate *main_window_private;
252 ModestTnyMsgReplyType reply_type;
253 ModestTnyMsgForwardType forward_type;
260 static GtkWindowClass *parent_class = NULL;
263 /* Private actions */
264 /* This is the context sensitive menu: */
265 static const GtkActionEntry modest_folder_view_action_entries [] = {
267 /* Folder View CSM actions */
268 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
269 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
270 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
271 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
272 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
273 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_csm_help) },
276 static const GtkActionEntry modest_header_view_action_entries [] = {
278 /* Header View CSM actions */
279 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
280 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
281 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
282 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
283 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
284 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
285 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
286 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
287 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
288 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
291 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
292 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
295 /************************************************************************/
298 modest_main_window_get_type (void)
300 static GType my_type = 0;
302 static const GTypeInfo my_info = {
303 sizeof(ModestMainWindowClass),
304 NULL, /* base init */
305 NULL, /* base finalize */
306 (GClassInitFunc) modest_main_window_class_init,
307 NULL, /* class finalize */
308 NULL, /* class data */
309 sizeof(ModestMainWindow),
311 (GInstanceInitFunc) modest_main_window_init,
314 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
322 modest_main_window_class_init (ModestMainWindowClass *klass)
324 GObjectClass *gobject_class;
325 gobject_class = (GObjectClass*) klass;
326 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
328 parent_class = g_type_class_peek_parent (klass);
329 gobject_class->finalize = modest_main_window_finalize;
331 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
333 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
334 modest_window_class->save_state_func = save_state;
335 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
336 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
337 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
341 modest_main_window_init (ModestMainWindow *obj)
343 ModestMainWindowPrivate *priv;
345 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
347 priv->queue_err_signals = NULL;
348 priv->msg_paned = NULL;
349 priv->main_paned = NULL;
350 priv->main_vbox = NULL;
351 priv->header_view = NULL;
352 priv->folder_view = NULL;
353 priv->contents_widget = NULL;
354 priv->accounts_popup = NULL;
355 priv->details_widget = NULL;
356 priv->empty_view = NULL;
357 priv->progress_widgets = NULL;
358 priv->progress_bar = NULL;
359 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
360 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
361 priv->wait_for_settings = TRUE;
362 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
363 priv->merge_ids = NULL;
364 priv->optimized_view = FALSE;
365 priv->send_receive_in_progress = FALSE;
366 priv->progress_bar_timeout = 0;
367 priv->restore_paned_timeout = 0;
368 priv->sighandlers = NULL;
369 priv->updating_banner = NULL;
370 priv->updating_banner_timeout = 0;
371 priv->opening_banner = NULL;
372 priv->opening_banner_timeout = 0;
373 priv->display_state = OSSO_DISPLAY_ON;
375 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
377 "applications_email_mainview");
381 modest_main_window_finalize (GObject *obj)
383 ModestMainWindowPrivate *priv;
385 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
387 /* Sanity check: shouldn't be needed, the window mgr should
388 call this function before */
389 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
390 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
392 if (priv->empty_view) {
393 g_object_unref (priv->empty_view);
394 priv->empty_view = NULL;
397 if (priv->header_view) {
398 g_object_unref (priv->header_view);
399 priv->header_view = NULL;
402 g_slist_free (priv->progress_widgets);
404 g_byte_array_free (priv->merge_ids, TRUE);
406 if (priv->progress_bar_timeout > 0) {
407 g_source_remove (priv->progress_bar_timeout);
408 priv->progress_bar_timeout = 0;
411 if (priv->updating_banner_timeout > 0) {
412 g_source_remove (priv->updating_banner_timeout);
413 priv->updating_banner_timeout = 0;
416 if (priv->updating_banner) {
417 gtk_widget_destroy (priv->updating_banner);
418 priv->updating_banner = NULL;
421 if (priv->opening_banner_timeout > 0) {
422 g_source_remove (priv->opening_banner_timeout);
423 priv->opening_banner_timeout = 0;
426 if (priv->opening_banner) {
427 gtk_widget_destroy (priv->opening_banner);
428 priv->opening_banner = NULL;
431 if (priv->restore_paned_timeout > 0) {
432 g_source_remove (priv->restore_paned_timeout);
433 priv->restore_paned_timeout = 0;
436 G_OBJECT_CLASS(parent_class)->finalize (obj);
440 modest_main_window_get_child_widget (ModestMainWindow *self,
441 ModestMainWindowWidgetType widget_type)
443 ModestMainWindowPrivate *priv;
446 g_return_val_if_fail (self && MODEST_IS_MAIN_WINDOW(self), NULL);
447 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
450 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
452 switch (widget_type) {
453 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
454 widget = (GtkWidget*)priv->header_view; break;
455 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
456 widget = (GtkWidget*)priv->folder_view; break;
461 /* Note that the window could have been destroyed, and so
462 their children, but still have some references */
463 return (widget && GTK_IS_WIDGET(widget)) ? GTK_WIDGET(widget) : NULL;
467 restore_paned_timeout_handler (gpointer *data)
469 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
470 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
473 /* Timeouts are outside the main lock */
474 gdk_threads_enter ();
475 if (GTK_WIDGET_VISIBLE (main_window)) {
476 conf = modest_runtime_get_conf ();
477 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
478 MODEST_CONF_MAIN_PANED_KEY);
480 gdk_threads_leave ();
487 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
490 ModestMainWindowPrivate *priv;
492 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
494 conf = modest_runtime_get_conf ();
496 modest_widget_memory_restore (conf, G_OBJECT(self),
497 MODEST_CONF_MAIN_WINDOW_KEY);
499 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
500 MODEST_CONF_HEADER_VIEW_KEY);
502 if (do_folder_view_too)
503 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
504 MODEST_CONF_FOLDER_VIEW_KEY);
506 /* modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned), */
507 /* MODEST_CONF_MAIN_PANED_KEY); */
509 g_timeout_add (250, (GSourceFunc) restore_paned_timeout_handler, self);
511 /* We need to force a redraw here in order to get the right
512 position of the horizontal paned separator */
513 gtk_widget_show (GTK_WIDGET (self));
518 save_state (ModestWindow *window)
521 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
522 ModestMainWindowPrivate *priv;
524 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
525 conf = modest_runtime_get_conf ();
527 modest_widget_memory_save (conf,G_OBJECT(self),
528 MODEST_CONF_MAIN_WINDOW_KEY);
529 /* Only save main paned position if we're in split mode */
530 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
531 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
532 MODEST_CONF_MAIN_PANED_KEY);
533 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
534 MODEST_CONF_FOLDER_VIEW_KEY);
538 compare_display_names (ModestAccountSettings *a,
539 ModestAccountSettings *b)
541 return g_utf8_collate (modest_account_settings_get_display_name (a),
542 modest_account_settings_get_display_name (b));
546 /* We use this function to prevent the send&receive CSM to be shown
547 when there are less than two account */
549 tap_and_hold_query_cb (GtkWidget *widget, GdkEvent *event)
555 update_menus (ModestMainWindow* self)
557 GSList *account_names, *iter, *accounts;
558 ModestMainWindowPrivate *priv;
559 ModestWindowPrivate *parent_priv;
560 ModestAccountMgr *mgr;
561 gint i, num_accounts;
563 gchar *default_account;
564 const gchar *active_account_name;
565 GtkWidget *send_receive_button, *item;
566 GtkAction *send_receive_all = NULL;
569 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
570 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
572 /* Get enabled account IDs */
573 mgr = modest_runtime_get_account_mgr ();
574 account_names = modest_account_mgr_account_names (mgr, TRUE);
575 iter = account_names;
579 ModestAccountSettings *settings =
580 modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
581 accounts = g_slist_prepend (accounts, settings);
585 modest_account_mgr_free_account_names (account_names);
586 account_names = NULL;
588 /* Order the list of accounts by its display name */
589 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
590 num_accounts = g_slist_length (accounts);
592 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
593 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
594 gtk_action_set_visible (send_receive_all, num_accounts > 0);
596 /* Delete old send&receive popup items. We can not just do a
597 menu_detach because it does not work well with
599 if (priv->accounts_popup)
600 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
601 (GtkCallback) gtk_widget_destroy, NULL);
603 /* Delete old entries in the View menu. Do not free groups, it
605 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
607 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
608 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
609 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
610 GTK_ACTION_GROUP (groups->data));
613 if (priv->merge_ids) {
614 for (i = 0; i < priv->merge_ids->len; i++)
615 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
616 g_byte_array_free (priv->merge_ids, TRUE);
618 /* We need to call this in order to ensure
619 that the new actions are added in the right
620 order (alphabetical) */
621 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
623 groups = g_list_next (groups);
625 priv->merge_ids = g_byte_array_sized_new (num_accounts);
627 /* Get send receive button */
628 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
629 "/ToolBar/ToolbarSendReceive");
631 /* Create the menu */
632 if (num_accounts > 1) {
633 if (!priv->accounts_popup)
634 priv->accounts_popup = gtk_menu_new ();
635 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
636 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
637 g_signal_connect (G_OBJECT (item),
639 G_CALLBACK (on_send_receive_csm_activated),
641 item = gtk_separator_menu_item_new ();
642 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
645 /* Create a new action group */
646 default_account = modest_account_mgr_get_default_account (mgr);
647 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
649 if (!active_account_name)
650 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
652 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
654 for (i = 0; i < num_accounts; i++) {
655 gchar *display_name = NULL;
656 const gchar *account_name;
657 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
660 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
663 account_name = modest_account_settings_get_account_name (settings);
665 if (default_account && account_name &&
666 !(strcmp (default_account, account_name) == 0)) {
667 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
668 modest_account_settings_get_display_name (settings));
670 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
671 modest_account_settings_get_display_name (settings));
676 /* Create action and add it to the action group. The
677 action name must be the account name, this way we
678 could know in the handlers the account to show */
679 if (settings && account_name) {
680 gchar* item_name, *refresh_action_name;
682 GtkAction *view_account_action, *refresh_account_action;
683 gchar *escaped_display_name;
685 escaped_display_name = modest_text_utils_escape_mnemonics (display_name);
687 view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
688 escaped_display_name, NULL, NULL, 0));
689 g_free (escaped_display_name);
690 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
691 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
692 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
694 if (active_account_name) {
695 if (active_account_name && account_name &&
696 (strcmp (active_account_name, account_name) == 0)) {
697 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
701 /* Add ui from account data. We allow 2^9-1 account
702 changes in a single execution because we're
703 downcasting the guint to a guint8 in order to use a
704 GByteArray. It should be enough :-) */
705 item_name = g_strconcat (account_name, "Menu", NULL);
706 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
707 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
708 gtk_ui_manager_add_ui (parent_priv->ui_manager,
710 "/MenuBar/ViewMenu/ViewMenuAdditions",
713 GTK_UI_MANAGER_MENUITEM,
716 /* Connect the action signal "activate" */
717 g_signal_connect_after (G_OBJECT (view_account_action),
719 G_CALLBACK (on_show_account_action_toggled),
722 /* Create the items for the Tools->Send&Receive submenu */
723 refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
724 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
725 display_name, NULL, NULL);
726 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
728 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
729 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
730 gtk_ui_manager_add_ui (parent_priv->ui_manager,
732 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
735 GTK_UI_MANAGER_MENUITEM,
737 g_free (refresh_action_name);
739 g_signal_connect_data (G_OBJECT (refresh_account_action),
741 G_CALLBACK (on_refresh_account_action_activated),
742 g_strdup (account_name),
743 (GClosureNotify) g_free,
746 /* Create item and add it to the send&receive
747 CSM. If there is only one account then
749 if (num_accounts > 1) {
750 GtkWidget *label = gtk_label_new(NULL);
751 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
752 if (default_account && (strcmp(account_name, default_account) == 0)) {
753 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
754 gtk_label_set_markup (GTK_LABEL (label), escaped);
757 gtk_label_set_text (GTK_LABEL (label), display_name);
760 item = gtk_menu_item_new ();
761 gtk_container_add (GTK_CONTAINER (item), label);
763 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup),
765 g_signal_connect_data (G_OBJECT (item),
767 G_CALLBACK (on_send_receive_csm_activated),
768 g_strdup (account_name),
769 (GClosureNotify) g_free,
776 g_free (display_name);
779 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
781 /* We cannot do this in the loop above because this relies on the action
782 * group being inserted. This makes the default account appear in bold.
783 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
784 for (i = 0; i < num_accounts; i++) {
785 gchar *item_name, *path;
787 ModestAccountSettings *settings;
788 const gchar *account_name;
791 settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
792 account_name = modest_account_settings_get_account_name (settings);
793 is_default = (account_name && default_account && !strcmp (account_name, default_account));
795 /* Get the item of the view menu */
796 item_name = g_strconcat (account_name, "Menu", NULL);
797 path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
798 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
802 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
803 if (GTK_IS_LABEL (child)) {
804 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
806 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
807 gtk_label_set_markup (GTK_LABEL (child), bold_name);
810 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
814 /* Get the item of the tools menu */
815 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
816 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
820 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
821 if (GTK_IS_LABEL (child)) {
822 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
824 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
825 gtk_label_set_markup (GTK_LABEL (child), bold_name);
828 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
833 g_object_unref (settings);
836 if (num_accounts > 1) {
837 /* Disconnect the tap-and-hold-query if it's connected */
838 if (modest_signal_mgr_is_connected (priv->sighandlers,
839 G_OBJECT (send_receive_button),
840 "tap-and-hold-query"))
841 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
842 G_OBJECT (send_receive_button),
843 "tap-and-hold-query");
845 /* Mandatory in order to view the menu contents */
846 gtk_widget_show_all (priv->accounts_popup);
848 /* Setup tap_and_hold just if was not done before*/
849 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
850 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
852 /* Connect the tap-and-hold-query in order not to show the CSM */
853 if (!modest_signal_mgr_is_connected (priv->sighandlers,
854 G_OBJECT (send_receive_button),
855 "tap-and-hold-query"))
856 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
857 G_OBJECT (send_receive_button),
858 "tap-and-hold-query",
859 G_CALLBACK (tap_and_hold_query_cb),
864 g_slist_free (accounts);
865 g_free (default_account);
868 /* Make sure that at least one account is viewed if there are any
869 * accounts, for instance when adding the first account: */
870 set_at_least_one_account_visible (self);
874 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
876 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
877 gtk_scrolled_window_add_with_viewport
878 (GTK_SCROLLED_WINDOW(win), widget);
880 gtk_container_add (GTK_CONTAINER(win),
891 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
893 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
895 GList *oerrsignals = priv->queue_err_signals;
896 while (oerrsignals) {
897 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
898 g_signal_handler_disconnect (esignal->queue, esignal->signal);
899 g_slice_free (QueueErrorSignal, esignal);
900 oerrsignals = g_list_next (oerrsignals);
902 g_list_free (priv->queue_err_signals);
903 priv->queue_err_signals = NULL;
908 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
910 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
913 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
917 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
919 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
921 /* Update visibility */
924 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
928 modest_main_window_disconnect_signals (ModestWindow *self)
930 ModestMainWindowPrivate *priv;
931 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
933 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
934 priv->sighandlers = NULL;
938 connect_signals (ModestMainWindow *self)
940 ModestWindowPrivate *parent_priv;
941 ModestMainWindowPrivate *priv;
944 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
945 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
950 modest_signal_mgr_connect (priv->sighandlers,
951 G_OBJECT(priv->folder_view), "key-press-event",
952 G_CALLBACK(on_inner_widgets_key_pressed), self);
954 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
955 "folder_selection_changed",
956 G_CALLBACK (on_folder_selection_changed),
959 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
960 "folder-display-name-changed",
961 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
964 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
966 G_CALLBACK (on_folder_view_focus_in),
969 /* Folder view CSM */
970 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
971 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
972 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
973 G_CALLBACK(_folder_view_csm_menu_activated),
977 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
978 G_CALLBACK(modest_ui_actions_on_header_selected), self);
980 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
981 G_CALLBACK(modest_ui_actions_on_header_activated), self);
983 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
984 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
986 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
987 G_CALLBACK(on_inner_widgets_key_pressed), self);
989 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
990 G_CALLBACK(on_msg_count_changed), self);
992 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
993 G_CALLBACK (on_header_view_focus_in), self);
995 modest_signal_mgr_connect (priv->sighandlers,
996 G_OBJECT (priv->header_view),
998 G_CALLBACK (on_updating_msg_list),
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);
1005 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
1006 G_CALLBACK(_header_view_csm_menu_activated),
1011 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
1012 G_CALLBACK (modest_main_window_window_state_event),
1014 /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
1015 * in destroy stage */
1016 g_signal_connect (G_OBJECT (self), "destroy", G_CALLBACK (on_window_destroy), NULL);
1018 g_signal_connect (G_OBJECT (self), "notify::visible", G_CALLBACK (on_window_hide), NULL);
1020 /* Mail Operation Queue */
1022 modest_signal_mgr_connect (priv->sighandlers,
1023 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
1025 G_CALLBACK (on_queue_changed), self);
1027 /* Track changes in the device name */
1029 modest_signal_mgr_connect (priv->sighandlers,
1030 G_OBJECT(modest_runtime_get_conf ()),
1032 G_CALLBACK (on_configuration_key_changed),
1035 /* Track account changes. We need to refresh the toolbar */
1037 modest_signal_mgr_connect (priv->sighandlers,
1038 G_OBJECT (modest_runtime_get_account_store ()),
1040 G_CALLBACK (on_account_inserted),
1043 modest_signal_mgr_connect (priv->sighandlers,
1044 G_OBJECT (modest_runtime_get_account_store ()),
1046 G_CALLBACK (on_account_removed),
1049 /* We need to refresh the send & receive menu to change the bold
1050 * account when the default account changes. */
1052 modest_signal_mgr_connect (priv->sighandlers,
1053 G_OBJECT (modest_runtime_get_account_mgr ()),
1054 "default_account_changed",
1055 G_CALLBACK (on_default_account_changed),
1060 modest_signal_mgr_connect (priv->sighandlers,
1061 G_OBJECT (modest_runtime_get_account_store ()),
1063 G_CALLBACK (on_account_changed),
1068 on_hildon_program_is_topmost_notify(GObject *self,
1069 GParamSpec *propert_param,
1072 HildonProgram *app = HILDON_PROGRAM (self);
1074 /* Note that use of hildon_program_set_can_hibernate()
1075 * is generally referred to as "setting the killable flag",
1076 * though hibernation does not seem equal to death.
1079 if (hildon_program_get_is_topmost (app)) {
1080 /* Prevent hibernation when the progam comes to the foreground,
1081 * because hibernation should only happen when the application
1082 * is in the background: */
1083 hildon_program_set_can_hibernate (app, FALSE);
1085 /* Remove new mail visual notifications */
1086 modest_platform_remove_new_mail_notifications (TRUE);
1088 /* Allow hibernation if the program has gone to the background: */
1090 /* However, prevent hibernation while the settings are being changed: */
1091 const gboolean hibernation_prevented =
1092 modest_window_mgr_get_hibernation_is_prevented (
1093 modest_runtime_get_window_mgr ());
1095 if (hibernation_prevented)
1096 hildon_program_set_can_hibernate (app, FALSE);
1098 /* Allow hibernation, after saving the state: */
1099 modest_osso_save_state();
1100 hildon_program_set_can_hibernate (app, TRUE);
1107 GtkWidget *folder_win;
1112 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1114 ShowHelper *helper = (ShowHelper *) user_data;
1115 GtkWidget *folder_win = helper->folder_win;
1116 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1117 ModestAccountMgr *mgr;
1119 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1120 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1122 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1124 /* Connect signals */
1125 connect_signals (MODEST_MAIN_WINDOW (self));
1127 /* Set account store */
1128 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1129 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1131 /* Load previous osso state, for instance if we are being restored from
1133 modest_osso_load_state ();
1135 /* Restore window & widget settings */
1136 priv->wait_for_settings = TRUE;
1137 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1138 priv->wait_for_settings = FALSE;
1140 /* Update the menus if there are accounts */
1141 mgr = modest_runtime_get_account_mgr();
1142 if (modest_account_mgr_has_accounts(mgr, TRUE))
1143 update_menus (MODEST_MAIN_WINDOW (self));
1145 /* Never call this function again (NOTE that it could happen
1146 as we hide the main window instead of closing it while
1147 there are operations ongoing) and free the helper */
1148 g_signal_handler_disconnect (self, helper->handler_id);
1149 g_slice_free (ShowHelper, helper);
1153 osso_display_event_cb (osso_display_state_t state,
1156 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1158 priv->display_state = state;
1160 /* Stop blinking if the screen becomes on */
1161 if (priv->display_state == OSSO_DISPLAY_ON)
1162 modest_platform_remove_new_mail_notifications (TRUE);
1166 modest_main_window_new (void)
1168 ModestMainWindow *self = NULL;
1169 ModestMainWindowPrivate *priv = NULL;
1170 ModestWindowPrivate *parent_priv = NULL;
1171 GtkWidget *folder_win = NULL;
1172 ModestDimmingRulesGroup *menu_rules_group = NULL;
1173 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1174 GtkActionGroup *action_group = NULL;
1175 GError *error = NULL;
1177 ModestConf *conf = NULL;
1178 GtkAction *action = NULL;
1179 GdkPixbuf *window_icon;
1182 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1183 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1184 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1186 parent_priv->ui_manager = gtk_ui_manager_new();
1187 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1189 action_group = gtk_action_group_new ("ModestMainWindowActions");
1190 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1192 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1193 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1195 /* Add common actions */
1196 gtk_action_group_add_actions (action_group,
1197 modest_action_entries,
1198 G_N_ELEMENTS (modest_action_entries),
1201 gtk_action_group_add_actions (action_group,
1202 modest_folder_view_action_entries,
1203 G_N_ELEMENTS (modest_folder_view_action_entries),
1206 gtk_action_group_add_actions (action_group,
1207 modest_header_view_action_entries,
1208 G_N_ELEMENTS (modest_header_view_action_entries),
1211 gtk_action_group_add_toggle_actions (action_group,
1212 modest_toggle_action_entries,
1213 G_N_ELEMENTS (modest_toggle_action_entries),
1216 gtk_action_group_add_toggle_actions (action_group,
1217 modest_main_window_toggle_action_entries,
1218 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1221 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1222 g_object_unref (action_group);
1224 /* Load the UI definition */
1225 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1226 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1227 if (error != NULL) {
1228 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1229 g_error_free (error);
1233 /* Add common dimming rules */
1234 modest_dimming_rules_group_add_rules (menu_rules_group,
1235 modest_main_window_menu_dimming_entries,
1236 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1237 MODEST_WINDOW (self));
1238 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1239 modest_main_window_toolbar_dimming_entries,
1240 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1241 MODEST_WINDOW (self));
1243 /* Insert dimming rules group for this window */
1244 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1245 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1246 g_object_unref (menu_rules_group);
1247 g_object_unref (toolbar_rules_group);
1249 /* Add accelerators */
1250 gtk_window_add_accel_group (GTK_WINDOW (self),
1251 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1253 /* Menubar. Update the state of some toggles */
1254 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1255 conf = modest_runtime_get_conf ();
1256 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1257 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1258 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1259 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1260 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1261 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1262 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1263 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1264 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1265 gtk_widget_show (parent_priv->menubar);
1267 /* Get device name */
1268 modest_maemo_utils_get_device_name ();
1272 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1273 g_object_ref (priv->header_view);
1274 if (!priv->header_view)
1275 g_printerr ("modest: cannot instantiate header view\n");
1276 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1277 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1278 MODEST_CONF_HEADER_VIEW_KEY);
1280 /* Other style properties of header view */
1281 g_object_set (G_OBJECT (priv->header_view),
1282 "rules-hint", FALSE,
1284 /* gtk_widget_show (priv->header_view); */
1287 priv->empty_view = create_empty_view ();
1288 gtk_widget_show (priv->empty_view);
1289 g_object_ref (priv->empty_view);
1291 /* Create scrolled windows */
1292 folder_win = gtk_scrolled_window_new (NULL, NULL);
1293 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1294 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1296 GTK_POLICY_AUTOMATIC);
1297 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1299 GTK_POLICY_AUTOMATIC);
1300 /* gtk_widget_show (priv->contents_widget); */
1303 priv->main_paned = gtk_hpaned_new ();
1304 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1305 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1306 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1308 /* putting it all together... */
1309 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1310 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1311 gtk_widget_show (priv->main_vbox);
1313 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1315 app = hildon_program_get_instance ();
1316 hildon_program_add_window (app, HILDON_WINDOW (self));
1318 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1319 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1321 /* Connect to "show" action. We delay the creation of some
1322 elements until that moment */
1323 helper = g_slice_new0 (ShowHelper);
1324 helper->folder_win = folder_win;
1325 helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1326 G_CALLBACK (modest_main_window_on_show),
1329 /* Set window icon */
1330 window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1332 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1333 g_object_unref (window_icon);
1336 /* Listen for changes in the screen, we don't want to show a
1337 led pattern when the display is on for example */
1338 osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1339 osso_display_event_cb,
1342 /* Dont't restore settings here,
1343 * because it requires a gtk_widget_show(),
1344 * and we don't want to do that until later,
1345 * so that the UI is not visible for non-menu D-Bus activation.
1348 return MODEST_WINDOW(self);
1352 modest_main_window_set_style (ModestMainWindow *self,
1353 ModestMainWindowStyle style)
1355 ModestMainWindowPrivate *priv;
1356 ModestWindowPrivate *parent_priv;
1359 GtkTreeSelection *sel;
1362 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1364 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1365 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1367 /* no change -> nothing to do */
1368 if (priv->style == style)
1371 /* Get toggle button and update the state if needed. This will
1372 happen only when the set_style is not invoked from the UI,
1373 for example when it's called from widget memory */
1374 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1375 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1376 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1377 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1378 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1379 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1380 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1383 /* We need to store the selection because it's lost when the
1384 widget is reparented */
1385 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1386 rows = gtk_tree_selection_get_selected_rows (sel, NULL);
1388 priv->style = style;
1390 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1392 if (!priv->wait_for_settings)
1393 modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT (priv->main_paned),
1394 MODEST_CONF_MAIN_PANED_KEY);
1395 /* Remove main paned */
1396 g_object_ref (priv->main_paned);
1397 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1399 /* Reparent the contents widget to the main vbox */
1400 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1403 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1404 /* Remove header view */
1405 g_object_ref (priv->contents_widget);
1406 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1408 /* Reparent the main paned */
1409 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1410 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1412 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
1416 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1418 g_return_if_reached ();
1421 /* Reselect the previously selected folders. We disable the
1422 dimming rules execution during that time because there is
1423 no need to work out it again and it could take a lot of
1424 time if all the headers are selected */
1426 modest_window_disable_dimming (MODEST_WINDOW (self));
1428 gtk_tree_selection_select_path (sel, (GtkTreePath *) list->data);
1429 list = g_list_next (list);
1431 modest_window_enable_dimming (MODEST_WINDOW (self));
1434 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1437 /* Let header view grab the focus if it's being shown */
1438 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1439 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1441 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
1442 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1444 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1447 /* Check dimming rules */
1448 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1449 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1452 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1455 ModestMainWindowStyle
1456 modest_main_window_get_style (ModestMainWindow *self)
1458 ModestMainWindowPrivate *priv;
1460 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1462 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1467 toolbar_resize (ModestMainWindow *self)
1469 ModestMainWindowPrivate *priv = NULL;
1470 ModestWindowPrivate *parent_priv = NULL;
1472 gint static_button_size;
1473 ModestWindowMgr *mgr;
1475 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1476 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1477 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1479 mgr = modest_runtime_get_window_mgr ();
1480 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1482 if (parent_priv->toolbar) {
1483 /* left size buttons */
1484 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1485 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1486 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1487 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1488 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1489 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1490 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1491 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1492 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1493 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1494 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1495 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1496 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1497 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1498 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1499 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1501 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1502 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1503 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1504 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1505 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1506 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1507 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1508 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1516 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1518 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1519 ModestWindowPrivate *parent_priv;
1520 ModestWindowMgr *mgr;
1521 gboolean is_fullscreen;
1522 GtkAction *fs_toggle_action;
1525 mgr = modest_runtime_get_window_mgr ();
1527 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1529 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1531 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1532 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1533 if (is_fullscreen != active) {
1534 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1537 toolbar_resize (MODEST_MAIN_WINDOW (widget));
1545 modest_main_window_show_toolbar (ModestWindow *self,
1546 gboolean show_toolbar)
1548 ModestMainWindowPrivate *priv = NULL;
1549 ModestWindowPrivate *parent_priv = NULL;
1550 GtkWidget *reply_button = NULL, *menu = NULL;
1551 GtkWidget *placeholder = NULL;
1553 const gchar *action_name;
1556 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1557 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1558 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1560 /* Set optimized view status */
1561 priv->optimized_view = !show_toolbar;
1563 if (!parent_priv->toolbar) {
1564 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1566 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1568 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1569 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1570 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1571 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1572 toolbar_resize (MODEST_MAIN_WINDOW (self));
1574 /* Add ProgressBar (Transfer toolbar) */
1575 priv->progress_bar = modest_progress_bar_new ();
1576 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1577 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1578 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1579 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1580 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1582 /* Connect cancel 'clicked' signal to abort progress mode */
1583 g_signal_connect(priv->cancel_toolitem, "clicked",
1584 G_CALLBACK(cancel_progressbar),
1587 /* Add it to the observers list */
1588 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1591 hildon_window_add_toolbar (HILDON_WINDOW (self),
1592 GTK_TOOLBAR (parent_priv->toolbar));
1594 /* Set reply button tap and hold menu */
1595 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1596 "/ToolBar/ToolbarMessageReply");
1597 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1598 "/ToolbarReplyCSM");
1599 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1601 /* Set send & receive button tap and hold menu */
1602 update_menus (MODEST_MAIN_WINDOW (self));
1606 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1607 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1608 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1610 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1611 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1612 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1614 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1616 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1620 /* Update also the actions (to update the toggles in the
1621 menus), we have to do it manually because some other window
1622 of the same time could have changed it (remember that the
1623 toolbar fullscreen mode is shared by all the windows of the
1625 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1626 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1628 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1630 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1631 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1636 on_account_inserted (TnyAccountStore *accoust_store,
1637 TnyAccount *account,
1640 /* Transport accounts and local ones (MMC and the Local
1641 folders account do now cause menu changes */
1642 if (TNY_IS_STORE_ACCOUNT (account) &&
1643 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1645 update_menus (MODEST_MAIN_WINDOW (user_data));
1650 on_default_account_changed (ModestAccountMgr* mgr,
1653 update_menus (MODEST_MAIN_WINDOW (user_data));
1657 on_account_removed (TnyAccountStore *accoust_store,
1658 TnyAccount *account,
1661 /* Transport accounts and local ones (MMC and the Local
1662 folders account do now cause menu changes */
1663 if (TNY_IS_STORE_ACCOUNT (account) &&
1664 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1665 update_menus (MODEST_MAIN_WINDOW (user_data));
1669 on_account_changed (TnyAccountStore *account_store,
1670 TnyAccount *account,
1673 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1675 /* Transport accounts and local ones (MMC and the Local
1676 folders account do now cause menu changes */
1677 if (TNY_IS_STORE_ACCOUNT (account)) {
1678 /* We need to refresh the details widget because it could have changed */
1679 if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1680 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1682 /* Update the menus as well, name could change */
1683 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1684 update_menus (MODEST_MAIN_WINDOW (user_data));
1689 * This function manages the key events used to navigate between
1690 * header and folder views (when the window is in split view)
1693 * -------------------------------------------------
1694 * HeaderView GDK_Left Move focus to folder view
1695 * FolderView GDK_Right Move focus to header view
1697 * There is no need to scroll to selected row, the widgets will be the
1698 * responsibles of doing that (probably managing the focus-in event
1701 on_inner_widgets_key_pressed (GtkWidget *widget,
1705 ModestMainWindowPrivate *priv;
1707 if (event->type == GDK_KEY_RELEASE)
1710 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1712 /* Do nothing if we're in SIMPLE style */
1713 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1716 if (MODEST_IS_HEADER_VIEW (widget)) {
1717 if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left)
1718 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1719 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1720 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1721 if (selected_headers > 1) {
1722 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1725 GtkTreePath * cursor_path;
1726 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1727 if (cursor_path == NULL) {
1728 GtkTreeSelection *selection;
1730 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1731 list = gtk_tree_selection_get_selected_rows (selection, NULL);
1734 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1735 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1740 } else if (MODEST_IS_FOLDER_VIEW (widget) &&
1741 (event->keyval == GDK_Right || event->keyval == GDK_KP_Right || event->keyval == GDK_Left || event->keyval == GDK_KP_Left)) {
1742 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1743 GtkTreePath *selected_path = NULL;
1744 GtkTreePath *start_path = NULL;
1745 GtkTreePath *end_path = NULL;
1747 GtkTreeSelection *selection;
1749 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1750 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1751 if (selected != NULL) {
1752 selected_path = (GtkTreePath *) selected->data;
1753 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1757 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1758 (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1760 /* Scroll to first path */
1761 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1770 gtk_tree_path_free (start_path);
1772 gtk_tree_path_free (end_path);
1773 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1774 g_list_free (selected);
1776 #endif /* GTK_CHECK_VERSION */
1778 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1785 set_alignment (GtkWidget *widget,
1788 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1789 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1793 create_empty_view (void)
1795 GtkLabel *label = NULL;
1796 GtkWidget *align = NULL;
1798 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1799 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1800 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1801 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1803 return GTK_WIDGET(align);
1807 * Free the returned string
1810 get_gray_color_markup (GtkWidget *styled_widget)
1812 gchar *gray_color_markup = NULL;
1813 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1814 /* Obtain the secondary text color. We need a realized widget, that's why
1815 we get styled_widget from outside */
1817 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1818 gray_color_markup = modest_text_utils_get_color_string (&color);
1819 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1821 if (!gray_color_markup)
1822 gray_color_markup = g_strdup ("#BBBBBB");
1824 return gray_color_markup;
1828 * Free the returned string
1831 create_device_name_visual_string (const gchar *device_name,
1832 const gchar *gray_color_markup)
1836 /* We have to use "" to fill the %s of the translation. We can
1837 not just use the device name because the device name is
1838 shown in a different color, so it could not be included
1839 into the <span> tag */
1840 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1841 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1852 GtkWidget *count_label;
1853 GtkWidget *msg_count_label;
1854 GtkWidget *size_label;
1855 gchar *color_markup;
1859 create_uint_label (const gchar *markup,
1863 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", markup, name, count);
1867 create_gchar_label (const gchar *markup,
1871 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", markup, name, count);
1875 update_folder_stats_status_cb (ModestFolderStats stats,
1878 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1881 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_folders"), stats.folders);
1882 gtk_label_set_markup (GTK_LABEL (widgets->count_label), label);
1885 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_messages"), stats.msg_count);
1886 gtk_label_set_markup (GTK_LABEL (widgets->msg_count_label), label);
1889 if (widgets->size_label) {
1890 tmp = modest_text_utils_get_display_size (stats.local_size);
1891 label = create_gchar_label (widgets->color_markup, _("mcen_fi_rootfolder_size"), tmp);
1892 gtk_label_set_markup (GTK_LABEL (widgets->size_label), label);
1899 update_folder_stats_cb (ModestFolderStats stats,
1902 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1905 update_folder_stats_status_cb (stats, user_data);
1907 /* frees. Note that the widgets could have been destroyed but
1908 we still keep a reference */
1909 g_free (widgets->color_markup);
1910 if (widgets->count_label)
1911 g_object_unref (widgets->count_label);
1912 if (widgets->msg_count_label)
1913 g_object_unref (widgets->msg_count_label);
1914 if (widgets->size_label)
1915 g_object_unref (widgets->size_label);
1916 g_slice_free (DetailsWidgets, widgets);
1920 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1922 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1927 gchar *gray_color_markup;
1928 DetailsWidgets *widgets;
1930 vbox = gtk_vbox_new (FALSE, 0);
1931 widgets = g_slice_new0 (DetailsWidgets);
1933 gray_color_markup = get_gray_color_markup (styled_widget);
1934 widgets->color_markup = g_strdup (gray_color_markup);
1936 /* Account description: */
1937 if (modest_tny_account_is_virtual_local_folders (account)
1938 || (modest_tny_account_is_memory_card_account (account))) {
1940 /* Get device name */
1941 gchar *device_name = NULL;
1942 if (modest_tny_account_is_virtual_local_folders (account))
1943 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1944 MODEST_CONF_DEVICE_NAME, NULL);
1946 device_name = g_strdup (tny_account_get_name (account));
1948 label = create_device_name_visual_string ((const gchar *) device_name,
1949 (const gchar *) gray_color_markup);
1950 label_w = gtk_label_new (NULL);
1951 gtk_label_set_markup (GTK_LABEL (label_w), label);
1952 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1953 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1954 g_free (device_name);
1957 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1958 gtk_box_pack_start (GTK_BOX (vbox),
1959 gtk_label_new (tny_account_get_name (account)),
1962 /* Other accounts, such as IMAP and POP: */
1967 /* Put proto in uppercase */
1968 proto = g_string_new (tny_account_get_proto (account));
1969 proto = g_string_ascii_up (proto);
1971 /* note: mcen_fi_localroot_description is something like "%s account"
1972 * however, we should display "%s account: %s"... therefore, ugly tmp */
1973 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1974 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1975 gray_color_markup, tmp, tny_account_get_name (account));
1978 label_w = gtk_label_new (NULL);
1979 gtk_label_set_markup (GTK_LABEL (label_w), label);
1980 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1981 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1982 g_string_free (proto, TRUE);
1988 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1989 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_messages"), 0);
1990 label_w = gtk_label_new (NULL);
1991 gtk_label_set_markup (GTK_LABEL (label_w), label);
1992 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1993 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1996 widgets->msg_count_label = g_object_ref (label_w);
1999 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_folders"), 0);
2000 label_w = gtk_label_new (NULL);
2001 gtk_label_set_markup (GTK_LABEL (label_w), label);
2002 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2003 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2006 widgets->count_label = g_object_ref (label_w);
2009 if (modest_tny_account_is_virtual_local_folders (account)
2010 || modest_tny_account_is_memory_card_account (account)) {
2012 label = create_gchar_label (gray_color_markup, _("mcen_fi_rootfolder_size"), "0");
2014 label_w = gtk_label_new (NULL);
2015 gtk_label_set_markup (GTK_LABEL (label_w), label);
2016 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2017 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2020 widgets->size_label = g_object_ref (label_w);
2022 } else if (TNY_IS_ACCOUNT(folder_store)) {
2023 TnyAccount *account = TNY_ACCOUNT(folder_store);
2025 time_t last_updated;
2026 const gchar *last_updated_string;
2027 /* Get last updated from configuration */
2028 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
2029 tny_account_get_id (account));
2031 if (last_updated > 0)
2032 last_updated_string = modest_text_utils_get_display_date(last_updated);
2034 last_updated_string = g_strdup (_("mcen_va_never"));
2036 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
2037 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
2038 label_w = gtk_label_new (NULL);
2039 gtk_label_set_markup (GTK_LABEL (label_w), label);
2040 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2041 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2045 g_free (gray_color_markup);
2047 /* Refresh folder stats asynchronously */
2048 modest_tny_folder_store_get_folder_stats (TNY_FOLDER_STORE (account),
2049 update_folder_stats_cb,
2050 update_folder_stats_status_cb,
2054 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
2060 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
2062 ModestMainWindowPrivate *priv = NULL;
2064 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2066 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2068 return priv->send_receive_in_progress;
2072 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
2074 GtkAction *action = NULL;
2075 GtkWidget *widget = NULL;
2076 ModestMainWindowPrivate *priv = NULL;
2078 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2079 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2081 priv->send_receive_in_progress = TRUE;
2083 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2084 gtk_action_set_sensitive (action, FALSE);
2085 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2086 /* gtk_action_set_sensitive (action, FALSE); */
2087 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2088 gtk_widget_set_sensitive (widget, FALSE);
2092 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
2094 GtkAction *action = NULL;
2095 GtkWidget *widget = NULL;
2096 ModestMainWindowPrivate *priv = NULL;
2098 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2099 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2101 priv->send_receive_in_progress = FALSE;
2103 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2104 gtk_action_set_sensitive (action, TRUE);
2105 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2106 /* gtk_action_set_sensitive (action, TRUE); */
2107 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2108 gtk_widget_set_sensitive (widget, TRUE);
2113 on_msg_count_changed (ModestHeaderView *header_view,
2115 TnyFolderChange *change,
2116 ModestMainWindow *main_window)
2118 gboolean refilter = FALSE;
2119 gboolean folder_empty = FALSE;
2120 gboolean all_marked_as_deleted = FALSE;
2121 ModestMainWindowPrivate *priv;
2123 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
2124 g_return_if_fail (TNY_IS_FOLDER(folder));
2125 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2127 if (change != NULL) {
2128 TnyFolderChangeChanged changed;
2130 changed = tny_folder_change_get_changed (change);
2131 /* If something changes */
2132 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
2133 folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
2135 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2137 /* Play a sound (if configured) and make the LED blink */
2138 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
2139 modest_platform_push_email_notification ();
2142 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
2145 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2148 /* Check if all messages are marked to be deleted */
2149 all_marked_as_deleted = modest_header_view_is_empty (header_view);
2150 folder_empty = folder_empty || all_marked_as_deleted;
2152 /* Set contents style of headers view */
2154 modest_main_window_set_contents_style (main_window,
2155 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2156 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
2158 modest_main_window_set_contents_style (main_window,
2159 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2163 modest_header_view_refilter (header_view);
2168 modest_main_window_set_contents_style (ModestMainWindow *self,
2169 ModestMainWindowContentsStyle style)
2171 ModestMainWindowPrivate *priv;
2173 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2175 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2177 /* We allow to set the same content style than the previously
2178 set if there are details, because it could happen when we're
2179 selecting different accounts consecutively */
2180 if ((priv->contents_style == style) &&
2181 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
2184 /* Remove previous child. Delete it if it was an account
2186 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
2188 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
2189 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
2192 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
2195 priv->contents_style = style;
2197 switch (priv->contents_style) {
2198 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
2199 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
2200 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2202 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2203 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
2205 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
2207 /* if we're started without main win, there may not be a folder
2208 * view. this fixes a GLib-Critical */
2209 if (priv->folder_view) {
2210 TnyFolderStore *selected_folderstore =
2211 modest_folder_view_get_selected (priv->folder_view);
2212 if (TNY_IS_ACCOUNT (selected_folderstore)) {
2213 priv->details_widget = create_details_widget (GTK_WIDGET (self),
2214 TNY_ACCOUNT (selected_folderstore));
2216 wrap_in_scrolled_window (priv->contents_widget,
2217 priv->details_widget);
2219 if (selected_folderstore)
2220 g_object_unref (selected_folderstore);
2221 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2224 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2225 gtk_widget_grab_focus (GTK_WIDGET (priv->details_widget));
2228 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
2229 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
2230 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2232 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2233 gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
2236 g_return_if_reached ();
2240 gtk_widget_show_all (priv->contents_widget);
2242 /* Recompute dimming rules */
2243 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2244 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2247 ModestMainWindowContentsStyle
2248 modest_main_window_get_contents_style (ModestMainWindow *self)
2250 ModestMainWindowPrivate *priv;
2252 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
2254 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2255 return priv->contents_style;
2260 on_configuration_key_changed (ModestConf* conf,
2262 ModestConfEvent event,
2263 ModestConfNotificationId id,
2264 ModestMainWindow *self)
2266 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2267 TnyAccount *account = NULL;
2269 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
2272 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
2275 if (priv->folder_view)
2276 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
2278 if (account && TNY_IS_ACCOUNT (account) &&
2279 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
2282 const gchar *device_name;
2283 gchar *new_text, *gray_color_markup;
2286 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
2287 label = GTK_LABEL (children->data);
2289 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2290 MODEST_CONF_DEVICE_NAME, NULL);
2292 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
2293 new_text = create_device_name_visual_string (device_name, gray_color_markup);
2295 gtk_label_set_markup (label, new_text);
2296 gtk_widget_show (GTK_WIDGET (label));
2298 g_free (gray_color_markup);
2300 g_list_free (children);
2302 g_object_unref (account);
2306 set_toolbar_transfer_mode (ModestMainWindow *self)
2308 ModestMainWindowPrivate *priv = NULL;
2310 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2312 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2314 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2316 if (priv->progress_bar_timeout > 0) {
2317 g_source_remove (priv->progress_bar_timeout);
2318 priv->progress_bar_timeout = 0;
2325 set_toolbar_mode (ModestMainWindow *self,
2326 ModestToolBarModes mode)
2328 ModestWindowPrivate *parent_priv = NULL;
2329 ModestMainWindowPrivate *priv = NULL;
2330 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2332 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2334 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2335 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2337 /* In case this was called before the toolbar exists: */
2338 if (!(parent_priv->toolbar))
2341 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2343 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2344 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2345 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2347 /* Sets current toolbar mode */
2348 priv->current_toolbar_mode = mode;
2350 /* Checks the dimming rules */
2351 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2352 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2354 /* Show and hide toolbar items */
2356 case TOOLBAR_MODE_NORMAL:
2358 gtk_action_set_visible (sort_action, TRUE);
2360 gtk_action_set_visible (refresh_action, TRUE);
2361 if (priv->progress_toolitem) {
2362 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2363 gtk_widget_hide (priv->progress_toolitem);
2365 if (priv->progress_bar)
2366 gtk_widget_hide (priv->progress_bar);
2369 gtk_action_set_visible (cancel_action, FALSE);
2371 /* Hide toolbar if optimized view is enabled */
2372 if (priv->optimized_view)
2373 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2375 case TOOLBAR_MODE_TRANSFER:
2377 gtk_action_set_visible (sort_action, FALSE);
2379 gtk_action_set_visible (refresh_action, FALSE);
2381 gtk_action_set_visible (cancel_action, TRUE);
2382 if (priv->progress_bar)
2383 gtk_widget_show (priv->progress_bar);
2384 if (priv->progress_toolitem) {
2385 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2386 gtk_widget_show (priv->progress_toolitem);
2389 /* Show toolbar if it's hiden (optimized view ) */
2390 if (priv->optimized_view)
2391 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2394 g_return_if_reached ();
2399 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2401 ModestMainWindowPrivate *priv;
2403 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2404 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2406 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2410 cancel_progressbar (GtkToolButton *toolbutton,
2411 ModestMainWindow *self)
2414 ModestMainWindowPrivate *priv;
2416 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2418 /* Get operation observers and cancel all the operations */
2419 tmp = priv->progress_widgets;
2421 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2422 tmp=g_slist_next(tmp);
2427 observers_empty (ModestMainWindow *self)
2430 ModestMainWindowPrivate *priv;
2431 gboolean is_empty = TRUE;
2432 guint pending_ops = 0;
2434 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2435 tmp = priv->progress_widgets;
2437 /* Check all observers */
2438 while (tmp && is_empty) {
2439 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2440 is_empty = pending_ops == 0;
2442 tmp = g_slist_next(tmp);
2450 * Gets the toolbar mode needed for each mail operation. It stores in
2451 * @mode_changed if the toolbar mode has changed or not
2453 static ModestToolBarModes
2454 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2455 ModestMailOperation *mail_op,
2456 gboolean *mode_changed)
2458 ModestToolBarModes mode;
2459 ModestMainWindowPrivate *priv;
2461 *mode_changed = FALSE;
2462 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2464 /* Get toolbar mode from operation id*/
2465 switch (modest_mail_operation_get_type_operation (mail_op)) {
2466 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
2467 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2468 mode = TOOLBAR_MODE_TRANSFER;
2469 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2470 *mode_changed = TRUE;
2473 mode = TOOLBAR_MODE_NORMAL;
2479 on_mail_operation_started (ModestMailOperation *mail_op,
2482 ModestMainWindow *self;
2483 ModestMailOperationTypeOperation op_type;
2484 ModestMainWindowPrivate *priv;
2485 ModestToolBarModes mode;
2487 gboolean mode_changed = FALSE;
2488 TnyAccount *account = NULL;
2490 self = MODEST_MAIN_WINDOW (user_data);
2491 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2493 /* Do not show progress for receiving operations if the
2494 account is the local account or the MMC one */
2495 op_type = modest_mail_operation_get_type_operation (mail_op);
2496 account = modest_mail_operation_get_account (mail_op);
2497 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2500 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2501 modest_tny_account_is_memory_card_account (account));
2503 g_object_unref (account);
2507 /* Show information banner. Remove old timeout */
2508 if (priv->opening_banner_timeout > 0) {
2509 g_source_remove (priv->opening_banner_timeout);
2510 priv->opening_banner_timeout = 0;
2512 /* Create a new timeout */
2513 priv->opening_banner_timeout =
2514 g_timeout_add (2000, show_opening_banner, self);
2517 /* Not every mail operation has account, noop does not */
2519 g_object_unref (account);
2521 /* Get toolbar mode from operation id*/
2522 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2524 /* Add operation observers and change toolbar if neccessary*/
2525 tmp = priv->progress_widgets;
2526 if (mode == TOOLBAR_MODE_TRANSFER) {
2528 GObject *source = modest_mail_operation_get_source(mail_op);
2529 if (G_OBJECT (self) == source) {
2530 set_toolbar_transfer_mode(self);
2532 g_object_unref (source);
2536 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2538 tmp = g_slist_next (tmp);
2542 /* Update the main menu as well, we need to explicitely do
2543 this in order to enable/disable accelerators */
2544 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2548 on_mail_operation_finished (ModestMailOperation *mail_op,
2551 ModestToolBarModes mode;
2552 ModestMailOperationTypeOperation op_type;
2554 ModestMainWindow *self;
2555 gboolean mode_changed;
2556 TnyAccount *account = NULL;
2557 ModestMainWindowPrivate *priv;
2559 self = MODEST_MAIN_WINDOW (user_data);
2560 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2562 /* The mail operation was not added to the progress objects if
2563 the account was the local account or the MMC one */
2564 op_type = modest_mail_operation_get_type_operation (mail_op);
2565 account = modest_mail_operation_get_account (mail_op);
2566 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2569 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2570 modest_tny_account_is_memory_card_account (account));
2572 g_object_unref (account);
2576 /* Remove old timeout */
2577 if (priv->opening_banner_timeout > 0) {
2578 g_source_remove (priv->opening_banner_timeout);
2579 priv->opening_banner_timeout = 0;
2582 /* Remove the banner if exists */
2583 if (priv->opening_banner) {
2584 gtk_widget_destroy (priv->opening_banner);
2585 priv->opening_banner = NULL;
2589 /* Not every mail operation has account, noop does not */
2591 g_object_unref (account);
2593 /* Get toolbar mode from operation id*/
2594 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2596 /* Change toolbar mode */
2597 tmp = priv->progress_widgets;
2598 if (mode == TOOLBAR_MODE_TRANSFER) {
2600 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2602 tmp = g_slist_next (tmp);
2605 /* If no more operations are being observed, NORMAL mode is enabled again */
2606 if (observers_empty (self)) {
2607 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2613 on_queue_changed (ModestMailOperationQueue *queue,
2614 ModestMailOperation *mail_op,
2615 ModestMailOperationQueueNotification type,
2616 ModestMainWindow *self)
2618 ModestMainWindowPrivate *priv;
2620 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2622 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2623 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2625 "operation-started",
2626 G_CALLBACK (on_mail_operation_started),
2628 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2630 "operation-finished",
2631 G_CALLBACK (on_mail_operation_finished),
2633 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2634 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2636 "operation-started");
2637 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2639 "operation-finished");
2644 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2646 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2648 ModestAccountMgr *mgr;
2649 ModestAccountSettings *settings;
2650 ModestServerAccountSettings *store_settings = NULL;
2652 /* Get account data */
2653 mgr = modest_runtime_get_account_mgr ();
2654 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2656 store_settings = modest_account_settings_get_store_settings (settings);
2658 /* Set the new visible & active account */
2659 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2660 const gchar *account_name;
2662 account_name = modest_account_settings_get_account_name (settings);
2664 modest_folder_view_set_account_id_of_visible_server_account
2666 modest_server_account_settings_get_account_name (store_settings));
2667 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2668 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2670 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2671 if (action != NULL) {
2672 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2673 modest_utils_toggle_action_set_active_block_notify (
2674 GTK_TOGGLE_ACTION (action),
2682 g_object_unref (store_settings);
2683 g_object_unref (settings);
2687 /* Make sure that at least one account is "viewed": */
2689 set_at_least_one_account_visible(ModestMainWindow *self)
2691 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2692 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2694 if (!(priv->folder_view)) {
2695 /* It is too early to do this. */
2699 const gchar *active_server_account_name =
2700 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2702 if (!active_server_account_name ||
2703 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2705 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2706 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2707 if (default_modest_name) {
2708 set_account_visible (self, default_modest_name);
2709 } else if (first_modest_name) {
2710 set_account_visible (self, first_modest_name);
2712 g_free (first_modest_name);
2713 g_free (default_modest_name);
2718 on_show_account_action_toggled (GtkToggleAction *action,
2721 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2723 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2724 if (gtk_toggle_action_get_active (action))
2725 set_account_visible (self, acc_name);
2729 refresh_account (const gchar *account_name)
2733 /* win must already exists here, obviously */
2734 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2737 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2741 /* If account_name == NULL, we must update all (option All) */
2743 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2745 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2750 on_refresh_account_action_activated (GtkAction *action,
2753 refresh_account ((const gchar*) user_data);
2757 on_send_receive_csm_activated (GtkMenuItem *item,
2760 refresh_account ((const gchar*) user_data);
2764 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2766 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2768 hildon_banner_show_information (NULL, NULL,
2769 _CS("ckct_ib_cannot_zoom_here"));
2775 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2777 ModestMainWindow *main_window = NULL;
2779 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2780 main_window = MODEST_MAIN_WINDOW (userdata);
2782 /* Update toolbar dimming state */
2783 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2784 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2790 on_header_view_focus_in (GtkWidget *widget,
2791 GdkEventFocus *event,
2794 ModestMainWindow *main_window = NULL;
2796 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2798 main_window = MODEST_MAIN_WINDOW (userdata);
2800 /* Update toolbar dimming state */
2801 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2802 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2808 on_folder_selection_changed (ModestFolderView *folder_view,
2809 TnyFolderStore *folder_store,
2811 ModestMainWindow *main_window)
2813 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2814 GtkAction *action = NULL;
2815 gboolean show_reply = TRUE;
2816 gboolean show_forward = TRUE;
2817 gboolean show_cancel_send = FALSE;
2818 gboolean show_clipboard = TRUE;
2819 gboolean show_delete = TRUE;
2822 if (TNY_IS_ACCOUNT (folder_store)) {
2823 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2824 } else if (TNY_IS_FOLDER (folder_store)) {
2825 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2826 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2827 TNY_FOLDER (folder_store));
2828 switch (folder_type) {
2829 case TNY_FOLDER_TYPE_DRAFTS:
2830 show_clipboard = show_delete = TRUE;
2831 show_reply = show_forward = show_cancel_send = FALSE;
2833 case TNY_FOLDER_TYPE_SENT:
2834 show_forward = show_clipboard = show_delete = TRUE;
2835 show_reply = show_cancel_send = FALSE;
2837 case TNY_FOLDER_TYPE_OUTBOX:
2838 show_clipboard = show_delete = show_cancel_send = TRUE;
2839 show_reply = show_forward = FALSE;
2841 case TNY_FOLDER_TYPE_INVALID:
2842 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2845 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2846 show_cancel_send = FALSE;
2849 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2850 show_cancel_send = FALSE;
2855 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2856 gtk_action_set_visible (action, show_reply);
2857 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2858 gtk_action_set_visible (action, show_reply);
2859 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2860 gtk_action_set_visible (action, show_forward);
2861 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2862 gtk_action_set_visible (action, show_cancel_send);
2863 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2864 gtk_action_set_visible (action, show_delete);
2866 /* We finally call to the ui actions handler, after updating properly
2867 * the header view CSM */
2868 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2872 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2873 GtkTreeModel *model,
2874 GtkTreeRowReference *row_reference,
2875 ModestMainWindow *self)
2877 ModestMainWindowPrivate *priv = NULL;
2878 GtkTreeModel *header_model = NULL;
2879 GtkTreePath *path = NULL;
2881 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2882 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2883 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2885 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2886 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2888 /* Do nothing if we changed the folder in the main view */
2889 if (header_model != model)
2892 /* Select the message in the header view */
2893 path = gtk_tree_row_reference_get_path (row_reference);
2894 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2896 gtk_tree_path_free (path);
2902 updating_banner_destroyed (gpointer data,
2903 GObject *where_the_object_was)
2905 ModestMainWindowPrivate *priv = NULL;
2907 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2909 priv->updating_banner = NULL;
2913 show_updating_banner (gpointer user_data)
2915 ModestMainWindowPrivate *priv = NULL;
2917 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2919 if (priv->updating_banner == NULL) {
2921 /* We're outside the main lock */
2922 gdk_threads_enter ();
2923 priv->updating_banner =
2924 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2925 _CS ("ckdg_pb_updating"));
2927 /* We need this because banners in Maemo could be
2928 destroyed by dialogs so we need to properly update
2929 our reference to it */
2930 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2931 updating_banner_destroyed,
2933 gdk_threads_leave ();
2936 /* Remove timeout */
2937 priv->updating_banner_timeout = 0;
2942 * We use this function to show/hide a progress banner showing
2943 * "Updating" while the header view is being filled. We're not showing
2944 * it unless the update takes more than 2 seconds
2946 * If starting = TRUE then the refresh is starting, otherwise it means
2947 * that is has just finished
2950 on_updating_msg_list (ModestHeaderView *header_view,
2954 ModestMainWindowPrivate *priv = NULL;
2956 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2958 /* Remove old timeout */
2959 if (priv->updating_banner_timeout > 0) {
2960 g_source_remove (priv->updating_banner_timeout);
2961 priv->updating_banner_timeout = 0;
2964 /* Create a new timeout */
2966 priv->updating_banner_timeout =
2967 g_timeout_add (2000, show_updating_banner, user_data);
2969 /* Remove the banner if exists */
2970 if (priv->updating_banner) {
2971 gtk_widget_destroy (priv->updating_banner);
2972 priv->updating_banner = NULL;
2978 modest_main_window_screen_is_on (ModestMainWindow *self)
2980 ModestMainWindowPrivate *priv = NULL;
2982 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2984 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2986 return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2990 remove_banners (ModestMainWindow *window)
2992 ModestMainWindowPrivate *priv;
2994 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2996 if (priv->opening_banner_timeout > 0) {
2997 g_source_remove (priv->opening_banner_timeout);
2998 priv->opening_banner_timeout = 0;
3001 if (priv->opening_banner != NULL) {
3002 gtk_widget_destroy (priv->opening_banner);
3003 priv->opening_banner = NULL;
3006 if (priv->updating_banner_timeout > 0) {
3007 g_source_remove (priv->updating_banner_timeout);
3008 priv->updating_banner_timeout = 0;
3011 if (priv->updating_banner != NULL) {
3012 gtk_widget_destroy (priv->updating_banner);
3013 priv->updating_banner = NULL;
3019 on_window_hide (GObject *gobject,
3023 g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
3025 if (!GTK_WIDGET_VISIBLE (gobject)) {
3026 TnyFolderStore *folder_store;
3027 ModestMainWindowPrivate *priv;
3029 /* Remove the currently shown banners */
3030 remove_banners (MODEST_MAIN_WINDOW (gobject));
3032 /* Force the folder view to sync the currently selected folder
3033 to save the read/unread status and to expunge messages */
3034 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
3035 folder_store = modest_folder_view_get_selected (priv->folder_view);
3036 if (TNY_IS_FOLDER (folder_store)) {
3037 ModestMailOperation *mail_op;
3039 mail_op = modest_mail_operation_new (NULL);
3040 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3042 modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
3043 g_object_unref (mail_op);
3044 g_object_unref (folder_store);
3050 on_window_destroy (GtkObject *widget,
3053 g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
3055 remove_banners (MODEST_MAIN_WINDOW (widget));
3059 opening_banner_destroyed (gpointer data,
3060 GObject *where_the_object_was)
3062 ModestMainWindowPrivate *priv = NULL;
3064 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
3066 priv->opening_banner = NULL;
3070 show_opening_banner (gpointer user_data)
3072 ModestMainWindowPrivate *priv = NULL;
3074 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
3076 if (priv->opening_banner == NULL) {
3078 /* We're outside the main lock */
3079 gdk_threads_enter ();
3080 priv->opening_banner =
3081 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
3082 _("mail_me_opening"));
3084 /* We need this because banners in Maemo could be
3085 destroyed by dialogs so we need to properly update
3086 our reference to it */
3087 g_object_weak_ref (G_OBJECT (priv->opening_banner),
3088 opening_banner_destroyed,
3091 /* We need this because banners in Maemo could be
3092 destroyed by dialogs so we need to properly update
3093 our reference to it */
3094 g_object_weak_ref (G_OBJECT (priv->updating_banner),
3095 updating_banner_destroyed,
3097 gdk_threads_leave ();
3100 /* Remove timeout */
3101 priv->opening_banner_timeout = 0;