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"
67 #ifdef MODEST_USE_LIBTIME
68 #include <clockd/libtime.h>
71 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
78 /* 'private'/'protected' functions */
79 static void modest_main_window_class_init (ModestMainWindowClass *klass);
80 static void modest_main_window_init (ModestMainWindow *obj);
81 static void modest_main_window_finalize (GObject *obj);
83 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
84 GdkEventWindowState *event,
87 static void connect_signals (ModestMainWindow *self);
89 static void modest_main_window_disconnect_signals (ModestWindow *self);
91 static void restore_settings (ModestMainWindow *self,
92 gboolean do_folder_view_too);
94 static void save_state (ModestWindow *self);
96 static void update_menus (ModestMainWindow* self);
98 static void modest_main_window_show_toolbar (ModestWindow *window,
99 gboolean show_toolbar);
101 static void cancel_progressbar (GtkToolButton *toolbutton,
102 ModestMainWindow *self);
104 static void on_queue_changed (ModestMailOperationQueue *queue,
105 ModestMailOperation *mail_op,
106 ModestMailOperationQueueNotification type,
107 ModestMainWindow *self);
109 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
111 static void on_account_inserted (TnyAccountStore *accoust_store,
115 static void on_account_removed (TnyAccountStore *accoust_store,
119 static void on_account_changed (TnyAccountStore *account_store,
123 static void on_default_account_changed (ModestAccountMgr* mgr,
126 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
130 static void on_configuration_key_changed (ModestConf* conf,
132 ModestConfEvent event,
133 ModestConfNotificationId id,
134 ModestMainWindow *self);
136 static void set_toolbar_mode (ModestMainWindow *self,
137 ModestToolBarModes mode);
139 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
141 static void on_show_account_action_toggled (GtkToggleAction *action,
144 static void on_refresh_account_action_activated (GtkAction *action,
147 static void on_send_receive_csm_activated (GtkMenuItem *item,
150 static void on_msg_count_changed (ModestHeaderView *header_view,
152 TnyFolderChange *change,
153 ModestMainWindow *main_window);
155 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
158 static GtkWidget * create_empty_view (void);
160 static gboolean on_folder_view_focus_in (GtkWidget *widget,
161 GdkEventFocus *event,
164 static gboolean on_header_view_focus_in (GtkWidget *widget,
165 GdkEventFocus *event,
168 static void on_folder_selection_changed (ModestFolderView *folder_view,
169 TnyFolderStore *folder_store,
171 ModestMainWindow *main_window);
173 static void set_at_least_one_account_visible(ModestMainWindow *self);
175 static void on_updating_msg_list (ModestHeaderView *header_view,
179 static gboolean restore_paned_timeout_handler (gpointer *data);
181 static gboolean show_opening_banner (gpointer user_data);
183 static void on_window_destroy (GtkObject *widget,
186 static void on_window_hide (GObject *gobject,
190 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
191 struct _ModestMainWindowPrivate {
192 GtkWidget *msg_paned;
193 GtkWidget *main_paned;
194 GtkWidget *main_vbox;
195 GtkWidget *contents_widget;
196 GtkWidget *empty_view;
198 /* Progress observers */
199 GtkWidget *progress_bar;
200 GSList *progress_widgets;
203 GtkWidget *progress_toolitem;
204 GtkWidget *cancel_toolitem;
205 GtkWidget *sort_toolitem;
206 GtkWidget *refresh_toolitem;
207 ModestToolBarModes current_toolbar_mode;
209 /* Merge ids used to add/remove accounts to the ViewMenu*/
210 GByteArray *merge_ids;
211 GtkActionGroup *view_additions_group;
213 /* On-demand widgets */
214 GtkWidget *accounts_popup;
215 GtkWidget *details_widget;
217 /* Optimized view enabled */
218 gboolean optimized_view;
220 /* Optimized view enabled */
221 gboolean send_receive_in_progress;
223 ModestHeaderView *header_view;
224 ModestFolderView *folder_view;
226 ModestMainWindowStyle style;
227 ModestMainWindowContentsStyle contents_style;
228 gboolean wait_for_settings;
230 guint progress_bar_timeout;
231 guint restore_paned_timeout;
233 /* Signal handler UIDs */
234 GList *queue_err_signals;
237 /* "Updating" banner for header view */
238 GtkWidget *updating_banner;
239 guint updating_banner_timeout;
241 /* "Opening" banner for header view */
242 GtkWidget *opening_banner;
243 guint opening_banner_timeout;
246 osso_display_state_t display_state;
248 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
249 MODEST_TYPE_MAIN_WINDOW, \
250 ModestMainWindowPrivate))
252 typedef struct _GetMsgAsyncHelper {
253 ModestMainWindowPrivate *main_window_private;
255 ModestTnyMsgReplyType reply_type;
256 ModestTnyMsgForwardType forward_type;
263 static GtkWindowClass *parent_class = NULL;
266 /* Private actions */
267 /* This is the context sensitive menu: */
268 static const GtkActionEntry modest_folder_view_action_entries [] = {
270 /* Folder View CSM actions */
271 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
272 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
273 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
274 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
275 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
276 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_csm_help) },
279 static const GtkActionEntry modest_header_view_action_entries [] = {
281 /* Header View CSM actions */
282 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
283 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
284 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
285 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
286 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
287 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
288 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
289 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
290 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
291 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
294 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
295 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
298 /************************************************************************/
301 modest_main_window_get_type (void)
303 static GType my_type = 0;
305 static const GTypeInfo my_info = {
306 sizeof(ModestMainWindowClass),
307 NULL, /* base init */
308 NULL, /* base finalize */
309 (GClassInitFunc) modest_main_window_class_init,
310 NULL, /* class finalize */
311 NULL, /* class data */
312 sizeof(ModestMainWindow),
314 (GInstanceInitFunc) modest_main_window_init,
317 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
325 modest_main_window_class_init (ModestMainWindowClass *klass)
327 GObjectClass *gobject_class;
328 gobject_class = (GObjectClass*) klass;
329 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
331 parent_class = g_type_class_peek_parent (klass);
332 gobject_class->finalize = modest_main_window_finalize;
334 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
336 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
337 modest_window_class->save_state_func = save_state;
338 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
339 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
340 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
344 modest_main_window_init (ModestMainWindow *obj)
346 ModestMainWindowPrivate *priv;
348 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
350 priv->queue_err_signals = NULL;
351 priv->msg_paned = NULL;
352 priv->main_paned = NULL;
353 priv->main_vbox = NULL;
354 priv->header_view = NULL;
355 priv->folder_view = NULL;
356 priv->contents_widget = NULL;
357 priv->accounts_popup = NULL;
358 priv->details_widget = NULL;
359 priv->empty_view = NULL;
360 priv->progress_widgets = NULL;
361 priv->progress_bar = NULL;
362 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
363 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
364 priv->wait_for_settings = TRUE;
365 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
366 priv->merge_ids = NULL;
367 priv->optimized_view = FALSE;
368 priv->send_receive_in_progress = FALSE;
369 priv->progress_bar_timeout = 0;
370 priv->restore_paned_timeout = 0;
371 priv->sighandlers = NULL;
372 priv->updating_banner = NULL;
373 priv->updating_banner_timeout = 0;
374 priv->opening_banner = NULL;
375 priv->opening_banner_timeout = 0;
376 priv->display_state = OSSO_DISPLAY_ON;
378 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
380 "applications_email_mainview");
384 modest_main_window_finalize (GObject *obj)
386 ModestMainWindowPrivate *priv;
388 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
390 /* Sanity check: shouldn't be needed, the window mgr should
391 call this function before */
392 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
393 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
395 if (priv->empty_view) {
396 g_object_unref (priv->empty_view);
397 priv->empty_view = NULL;
400 if (priv->header_view) {
401 g_object_unref (priv->header_view);
402 priv->header_view = NULL;
405 g_slist_free (priv->progress_widgets);
407 g_byte_array_free (priv->merge_ids, TRUE);
409 if (priv->progress_bar_timeout > 0) {
410 g_source_remove (priv->progress_bar_timeout);
411 priv->progress_bar_timeout = 0;
414 if (priv->updating_banner_timeout > 0) {
415 g_source_remove (priv->updating_banner_timeout);
416 priv->updating_banner_timeout = 0;
419 if (priv->updating_banner) {
420 gtk_widget_destroy (priv->updating_banner);
421 priv->updating_banner = NULL;
424 if (priv->opening_banner_timeout > 0) {
425 g_source_remove (priv->opening_banner_timeout);
426 priv->opening_banner_timeout = 0;
429 if (priv->opening_banner) {
430 gtk_widget_destroy (priv->opening_banner);
431 priv->opening_banner = NULL;
434 if (priv->restore_paned_timeout > 0) {
435 g_source_remove (priv->restore_paned_timeout);
436 priv->restore_paned_timeout = 0;
439 G_OBJECT_CLASS(parent_class)->finalize (obj);
443 modest_main_window_get_child_widget (ModestMainWindow *self,
444 ModestMainWindowWidgetType widget_type)
446 ModestMainWindowPrivate *priv;
449 g_return_val_if_fail (self && MODEST_IS_MAIN_WINDOW(self), NULL);
450 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
453 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
455 switch (widget_type) {
456 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
457 widget = (GtkWidget*)priv->header_view; break;
458 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
459 widget = (GtkWidget*)priv->folder_view; break;
464 /* Note that the window could have been destroyed, and so
465 their children, but still have some references */
466 return (widget && GTK_IS_WIDGET(widget)) ? GTK_WIDGET(widget) : NULL;
470 restore_paned_timeout_handler (gpointer *data)
472 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
473 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
476 /* Timeouts are outside the main lock */
477 gdk_threads_enter ();
478 if (GTK_WIDGET_VISIBLE (main_window)) {
479 conf = modest_runtime_get_conf ();
480 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
481 MODEST_CONF_MAIN_PANED_KEY);
483 gdk_threads_leave ();
490 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
493 ModestMainWindowPrivate *priv;
495 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
497 conf = modest_runtime_get_conf ();
499 modest_widget_memory_restore (conf, G_OBJECT(self),
500 MODEST_CONF_MAIN_WINDOW_KEY);
502 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
503 MODEST_CONF_HEADER_VIEW_KEY);
505 if (do_folder_view_too)
506 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
507 MODEST_CONF_FOLDER_VIEW_KEY);
509 /* modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned), */
510 /* MODEST_CONF_MAIN_PANED_KEY); */
512 g_timeout_add (250, (GSourceFunc) restore_paned_timeout_handler, self);
514 /* We need to force a redraw here in order to get the right
515 position of the horizontal paned separator */
516 gtk_widget_show (GTK_WIDGET (self));
521 save_state (ModestWindow *window)
524 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
525 ModestMainWindowPrivate *priv;
527 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
528 conf = modest_runtime_get_conf ();
530 modest_widget_memory_save (conf,G_OBJECT(self),
531 MODEST_CONF_MAIN_WINDOW_KEY);
532 /* Only save main paned position if we're in split mode */
533 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
534 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
535 MODEST_CONF_MAIN_PANED_KEY);
536 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
537 MODEST_CONF_FOLDER_VIEW_KEY);
541 compare_display_names (ModestAccountSettings *a,
542 ModestAccountSettings *b)
544 return g_utf8_collate (modest_account_settings_get_display_name (a),
545 modest_account_settings_get_display_name (b));
549 /* We use this function to prevent the send&receive CSM to be shown
550 when there are less than two account */
552 tap_and_hold_query_cb (GtkWidget *widget, GdkEvent *event)
558 update_menus (ModestMainWindow* self)
560 GSList *account_names, *iter, *accounts;
561 ModestMainWindowPrivate *priv;
562 ModestWindowPrivate *parent_priv;
563 ModestAccountMgr *mgr;
564 gint i, num_accounts;
566 gchar *default_account;
567 const gchar *active_account_name;
568 GtkWidget *send_receive_button, *item;
569 GtkAction *send_receive_all = NULL;
572 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
573 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
575 /* Get enabled account IDs */
576 mgr = modest_runtime_get_account_mgr ();
577 account_names = modest_account_mgr_account_names (mgr, TRUE);
578 iter = account_names;
582 ModestAccountSettings *settings =
583 modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
584 accounts = g_slist_prepend (accounts, settings);
588 modest_account_mgr_free_account_names (account_names);
589 account_names = NULL;
591 /* Order the list of accounts by its display name */
592 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
593 num_accounts = g_slist_length (accounts);
595 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
596 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
597 gtk_action_set_visible (send_receive_all, num_accounts > 0);
599 /* Delete old send&receive popup items. We can not just do a
600 menu_detach because it does not work well with
602 if (priv->accounts_popup)
603 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
604 (GtkCallback) gtk_widget_destroy, NULL);
606 /* Delete old entries in the View menu. Do not free groups, it
608 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
610 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
611 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
612 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
613 GTK_ACTION_GROUP (groups->data));
616 if (priv->merge_ids) {
617 for (i = 0; i < priv->merge_ids->len; i++)
618 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
619 g_byte_array_free (priv->merge_ids, TRUE);
621 /* We need to call this in order to ensure
622 that the new actions are added in the right
623 order (alphabetical) */
624 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
626 groups = g_list_next (groups);
628 priv->merge_ids = g_byte_array_sized_new (num_accounts);
630 /* Get send receive button */
631 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
632 "/ToolBar/ToolbarSendReceive");
634 /* Create the menu */
635 if (num_accounts > 1) {
636 if (!priv->accounts_popup)
637 priv->accounts_popup = gtk_menu_new ();
638 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
639 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
640 g_signal_connect (G_OBJECT (item),
642 G_CALLBACK (on_send_receive_csm_activated),
644 item = gtk_separator_menu_item_new ();
645 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
648 /* Create a new action group */
649 default_account = modest_account_mgr_get_default_account (mgr);
650 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
652 if (!active_account_name)
653 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
655 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
657 for (i = 0; i < num_accounts; i++) {
658 gchar *display_name = NULL;
659 const gchar *account_name;
660 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
663 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
666 account_name = modest_account_settings_get_account_name (settings);
668 if (default_account && account_name &&
669 !(strcmp (default_account, account_name) == 0)) {
670 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
671 modest_account_settings_get_display_name (settings));
673 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
674 modest_account_settings_get_display_name (settings));
679 /* Create action and add it to the action group. The
680 action name must be the account name, this way we
681 could know in the handlers the account to show */
682 if (settings && account_name) {
683 gchar* item_name, *refresh_action_name;
685 GtkAction *view_account_action, *refresh_account_action;
686 gchar *escaped_display_name;
688 escaped_display_name = modest_text_utils_escape_mnemonics (display_name);
690 view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
691 escaped_display_name, NULL, NULL, 0));
692 g_free (escaped_display_name);
693 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
694 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
695 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
697 if (active_account_name) {
698 if (active_account_name && account_name &&
699 (strcmp (active_account_name, account_name) == 0)) {
700 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
704 /* Add ui from account data. We allow 2^9-1 account
705 changes in a single execution because we're
706 downcasting the guint to a guint8 in order to use a
707 GByteArray. It should be enough :-) */
708 item_name = g_strconcat (account_name, "Menu", NULL);
709 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
710 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
711 gtk_ui_manager_add_ui (parent_priv->ui_manager,
713 "/MenuBar/ViewMenu/ViewMenuAdditions",
716 GTK_UI_MANAGER_MENUITEM,
719 /* Connect the action signal "activate" */
720 g_signal_connect_after (G_OBJECT (view_account_action),
722 G_CALLBACK (on_show_account_action_toggled),
725 /* Create the items for the Tools->Send&Receive submenu */
726 refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
727 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
728 display_name, NULL, NULL);
729 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
731 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
732 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
733 gtk_ui_manager_add_ui (parent_priv->ui_manager,
735 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
738 GTK_UI_MANAGER_MENUITEM,
740 g_free (refresh_action_name);
742 g_signal_connect_data (G_OBJECT (refresh_account_action),
744 G_CALLBACK (on_refresh_account_action_activated),
745 g_strdup (account_name),
746 (GClosureNotify) g_free,
749 /* Create item and add it to the send&receive
750 CSM. If there is only one account then
752 if (num_accounts > 1) {
753 GtkWidget *label = gtk_label_new(NULL);
754 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
755 if (default_account && (strcmp(account_name, default_account) == 0)) {
756 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
757 gtk_label_set_markup (GTK_LABEL (label), escaped);
760 gtk_label_set_text (GTK_LABEL (label), display_name);
763 item = gtk_menu_item_new ();
764 gtk_container_add (GTK_CONTAINER (item), label);
766 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup),
768 g_signal_connect_data (G_OBJECT (item),
770 G_CALLBACK (on_send_receive_csm_activated),
771 g_strdup (account_name),
772 (GClosureNotify) g_free,
779 g_free (display_name);
782 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
784 /* We cannot do this in the loop above because this relies on the action
785 * group being inserted. This makes the default account appear in bold.
786 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
787 for (i = 0; i < num_accounts; i++) {
788 gchar *item_name, *path;
790 ModestAccountSettings *settings;
791 const gchar *account_name;
794 settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
795 account_name = modest_account_settings_get_account_name (settings);
796 is_default = (account_name && default_account && !strcmp (account_name, default_account));
798 /* Get the item of the view menu */
799 item_name = g_strconcat (account_name, "Menu", NULL);
800 path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
801 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
805 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
806 if (GTK_IS_LABEL (child)) {
807 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
809 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
810 gtk_label_set_markup (GTK_LABEL (child), bold_name);
813 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
817 /* Get the item of the tools menu */
818 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
819 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
823 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
824 if (GTK_IS_LABEL (child)) {
825 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
827 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
828 gtk_label_set_markup (GTK_LABEL (child), bold_name);
831 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
836 g_object_unref (settings);
839 if (num_accounts > 1) {
840 /* Disconnect the tap-and-hold-query if it's connected */
841 if (modest_signal_mgr_is_connected (priv->sighandlers,
842 G_OBJECT (send_receive_button),
843 "tap-and-hold-query"))
844 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
845 G_OBJECT (send_receive_button),
846 "tap-and-hold-query");
848 /* Mandatory in order to view the menu contents */
849 gtk_widget_show_all (priv->accounts_popup);
851 /* Setup tap_and_hold just if was not done before*/
852 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
853 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
855 /* Connect the tap-and-hold-query in order not to show the CSM */
856 if (!modest_signal_mgr_is_connected (priv->sighandlers,
857 G_OBJECT (send_receive_button),
858 "tap-and-hold-query"))
859 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
860 G_OBJECT (send_receive_button),
861 "tap-and-hold-query",
862 G_CALLBACK (tap_and_hold_query_cb),
867 g_slist_free (accounts);
868 g_free (default_account);
871 /* Make sure that at least one account is viewed if there are any
872 * accounts, for instance when adding the first account: */
873 set_at_least_one_account_visible (self);
877 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
879 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
880 gtk_scrolled_window_add_with_viewport
881 (GTK_SCROLLED_WINDOW(win), widget);
883 gtk_container_add (GTK_CONTAINER(win),
894 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
896 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
898 GList *oerrsignals = priv->queue_err_signals;
899 while (oerrsignals) {
900 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
901 g_signal_handler_disconnect (esignal->queue, esignal->signal);
902 g_slice_free (QueueErrorSignal, esignal);
903 oerrsignals = g_list_next (oerrsignals);
905 g_list_free (priv->queue_err_signals);
906 priv->queue_err_signals = NULL;
911 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
913 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
916 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
920 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
922 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
924 /* Update visibility */
927 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
931 modest_main_window_disconnect_signals (ModestWindow *self)
933 ModestMainWindowPrivate *priv;
934 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
936 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
937 priv->sighandlers = NULL;
941 connect_signals (ModestMainWindow *self)
943 ModestWindowPrivate *parent_priv;
944 ModestMainWindowPrivate *priv;
947 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
948 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
953 modest_signal_mgr_connect (priv->sighandlers,
954 G_OBJECT(priv->folder_view), "key-press-event",
955 G_CALLBACK(on_inner_widgets_key_pressed), self);
957 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
958 "folder_selection_changed",
959 G_CALLBACK (on_folder_selection_changed),
962 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
963 "folder-display-name-changed",
964 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
967 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
969 G_CALLBACK (on_folder_view_focus_in),
972 /* Folder view CSM */
973 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
974 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
975 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
976 G_CALLBACK(_folder_view_csm_menu_activated),
980 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
981 G_CALLBACK(modest_ui_actions_on_header_selected), self);
983 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
984 G_CALLBACK(modest_ui_actions_on_header_activated), self);
986 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
987 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
989 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
990 G_CALLBACK(on_inner_widgets_key_pressed), self);
992 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
993 G_CALLBACK(on_msg_count_changed), self);
995 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
996 G_CALLBACK (on_header_view_focus_in), self);
998 modest_signal_mgr_connect (priv->sighandlers,
999 G_OBJECT (priv->header_view),
1000 "updating-msg-list",
1001 G_CALLBACK (on_updating_msg_list),
1004 /* Header view CSM */
1005 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
1006 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
1008 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
1009 G_CALLBACK(_header_view_csm_menu_activated),
1014 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
1015 G_CALLBACK (modest_main_window_window_state_event),
1017 /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
1018 * in destroy stage */
1019 g_signal_connect (G_OBJECT (self), "destroy", G_CALLBACK (on_window_destroy), NULL);
1021 g_signal_connect (G_OBJECT (self), "notify::visible", G_CALLBACK (on_window_hide), NULL);
1023 /* Mail Operation Queue */
1025 modest_signal_mgr_connect (priv->sighandlers,
1026 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
1028 G_CALLBACK (on_queue_changed), self);
1030 /* Track changes in the device name */
1032 modest_signal_mgr_connect (priv->sighandlers,
1033 G_OBJECT(modest_runtime_get_conf ()),
1035 G_CALLBACK (on_configuration_key_changed),
1038 /* Track account changes. We need to refresh the toolbar */
1040 modest_signal_mgr_connect (priv->sighandlers,
1041 G_OBJECT (modest_runtime_get_account_store ()),
1043 G_CALLBACK (on_account_inserted),
1046 modest_signal_mgr_connect (priv->sighandlers,
1047 G_OBJECT (modest_runtime_get_account_store ()),
1049 G_CALLBACK (on_account_removed),
1052 /* We need to refresh the send & receive menu to change the bold
1053 * account when the default account changes. */
1055 modest_signal_mgr_connect (priv->sighandlers,
1056 G_OBJECT (modest_runtime_get_account_mgr ()),
1057 "default_account_changed",
1058 G_CALLBACK (on_default_account_changed),
1063 modest_signal_mgr_connect (priv->sighandlers,
1064 G_OBJECT (modest_runtime_get_account_store ()),
1066 G_CALLBACK (on_account_changed),
1071 on_hildon_program_is_topmost_notify(GObject *self,
1072 GParamSpec *propert_param,
1075 HildonProgram *app = HILDON_PROGRAM (self);
1077 /* Note that use of hildon_program_set_can_hibernate()
1078 * is generally referred to as "setting the killable flag",
1079 * though hibernation does not seem equal to death.
1082 if (hildon_program_get_is_topmost (app)) {
1083 /* Prevent hibernation when the progam comes to the foreground,
1084 * because hibernation should only happen when the application
1085 * is in the background: */
1086 hildon_program_set_can_hibernate (app, FALSE);
1088 /* Remove new mail visual notifications */
1089 modest_platform_remove_new_mail_notifications (TRUE);
1091 /* Allow hibernation if the program has gone to the background: */
1093 /* However, prevent hibernation while the settings are being changed: */
1094 const gboolean hibernation_prevented =
1095 modest_window_mgr_get_hibernation_is_prevented (
1096 modest_runtime_get_window_mgr ());
1098 if (hibernation_prevented)
1099 hildon_program_set_can_hibernate (app, FALSE);
1101 /* Allow hibernation, after saving the state: */
1102 modest_osso_save_state();
1103 hildon_program_set_can_hibernate (app, TRUE);
1110 GtkWidget *folder_win;
1115 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1117 ShowHelper *helper = (ShowHelper *) user_data;
1118 GtkWidget *folder_win = helper->folder_win;
1119 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1120 ModestAccountMgr *mgr;
1122 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1123 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1125 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1127 /* Connect signals */
1128 connect_signals (MODEST_MAIN_WINDOW (self));
1130 /* Set account store */
1131 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1132 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1134 /* Load previous osso state, for instance if we are being restored from
1136 modest_osso_load_state ();
1138 /* Restore window & widget settings */
1139 priv->wait_for_settings = TRUE;
1140 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1141 priv->wait_for_settings = FALSE;
1143 /* Update the menus if there are accounts */
1144 mgr = modest_runtime_get_account_mgr();
1145 if (modest_account_mgr_has_accounts(mgr, TRUE))
1146 update_menus (MODEST_MAIN_WINDOW (self));
1148 /* Never call this function again (NOTE that it could happen
1149 as we hide the main window instead of closing it while
1150 there are operations ongoing) and free the helper */
1151 g_signal_handler_disconnect (self, helper->handler_id);
1152 g_slice_free (ShowHelper, helper);
1156 osso_display_event_cb (osso_display_state_t state,
1159 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1161 priv->display_state = state;
1163 /* Stop blinking if the screen becomes on */
1164 if (priv->display_state == OSSO_DISPLAY_ON)
1165 modest_platform_remove_new_mail_notifications (TRUE);
1169 modest_main_window_new (void)
1171 ModestMainWindow *self = NULL;
1172 ModestMainWindowPrivate *priv = NULL;
1173 ModestWindowPrivate *parent_priv = NULL;
1174 GtkWidget *folder_win = NULL;
1175 ModestDimmingRulesGroup *menu_rules_group = NULL;
1176 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1177 GtkActionGroup *action_group = NULL;
1178 GError *error = NULL;
1180 ModestConf *conf = NULL;
1181 GtkAction *action = NULL;
1182 GdkPixbuf *window_icon;
1185 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1186 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1187 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1189 parent_priv->ui_manager = gtk_ui_manager_new();
1190 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1192 action_group = gtk_action_group_new ("ModestMainWindowActions");
1193 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1195 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1196 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1198 /* Add common actions */
1199 gtk_action_group_add_actions (action_group,
1200 modest_action_entries,
1201 G_N_ELEMENTS (modest_action_entries),
1204 gtk_action_group_add_actions (action_group,
1205 modest_folder_view_action_entries,
1206 G_N_ELEMENTS (modest_folder_view_action_entries),
1209 gtk_action_group_add_actions (action_group,
1210 modest_header_view_action_entries,
1211 G_N_ELEMENTS (modest_header_view_action_entries),
1214 gtk_action_group_add_toggle_actions (action_group,
1215 modest_toggle_action_entries,
1216 G_N_ELEMENTS (modest_toggle_action_entries),
1219 gtk_action_group_add_toggle_actions (action_group,
1220 modest_main_window_toggle_action_entries,
1221 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1224 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1225 g_object_unref (action_group);
1227 /* Load the UI definition */
1228 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1229 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1230 if (error != NULL) {
1231 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1232 g_error_free (error);
1236 /* Add common dimming rules */
1237 modest_dimming_rules_group_add_rules (menu_rules_group,
1238 modest_main_window_menu_dimming_entries,
1239 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1240 MODEST_WINDOW (self));
1241 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1242 modest_main_window_toolbar_dimming_entries,
1243 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1244 MODEST_WINDOW (self));
1246 /* Insert dimming rules group for this window */
1247 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1248 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1249 g_object_unref (menu_rules_group);
1250 g_object_unref (toolbar_rules_group);
1252 /* Add accelerators */
1253 gtk_window_add_accel_group (GTK_WINDOW (self),
1254 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1256 /* Menubar. Update the state of some toggles */
1257 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1258 conf = modest_runtime_get_conf ();
1259 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1260 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1261 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1262 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1263 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1264 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1265 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1266 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1267 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1268 gtk_widget_show (parent_priv->menubar);
1270 /* Get device name */
1271 modest_maemo_utils_get_device_name ();
1275 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1276 g_object_ref (priv->header_view);
1277 if (!priv->header_view)
1278 g_printerr ("modest: cannot instantiate header view\n");
1279 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1280 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1281 MODEST_CONF_HEADER_VIEW_KEY);
1283 /* Other style properties of header view */
1284 g_object_set (G_OBJECT (priv->header_view),
1285 "rules-hint", FALSE,
1287 /* gtk_widget_show (priv->header_view); */
1290 priv->empty_view = create_empty_view ();
1291 gtk_widget_show (priv->empty_view);
1292 g_object_ref (priv->empty_view);
1294 /* Create scrolled windows */
1295 folder_win = gtk_scrolled_window_new (NULL, NULL);
1296 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1297 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1299 GTK_POLICY_AUTOMATIC);
1300 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1302 GTK_POLICY_AUTOMATIC);
1303 /* gtk_widget_show (priv->contents_widget); */
1306 priv->main_paned = gtk_hpaned_new ();
1307 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1308 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1309 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1311 /* putting it all together... */
1312 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1313 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1314 gtk_widget_show (priv->main_vbox);
1316 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1318 app = hildon_program_get_instance ();
1319 hildon_program_add_window (app, HILDON_WINDOW (self));
1321 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1322 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1324 /* Connect to "show" action. We delay the creation of some
1325 elements until that moment */
1326 helper = g_slice_new0 (ShowHelper);
1327 helper->folder_win = folder_win;
1328 helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1329 G_CALLBACK (modest_main_window_on_show),
1332 /* Set window icon */
1333 window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1335 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1336 g_object_unref (window_icon);
1339 /* Listen for changes in the screen, we don't want to show a
1340 led pattern when the display is on for example */
1341 osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1342 osso_display_event_cb,
1345 /* Dont't restore settings here,
1346 * because it requires a gtk_widget_show(),
1347 * and we don't want to do that until later,
1348 * so that the UI is not visible for non-menu D-Bus activation.
1351 return MODEST_WINDOW(self);
1355 modest_main_window_set_style (ModestMainWindow *self,
1356 ModestMainWindowStyle style)
1358 ModestMainWindowPrivate *priv;
1359 ModestWindowPrivate *parent_priv;
1362 GtkTreeSelection *sel;
1365 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1367 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1368 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1370 /* no change -> nothing to do */
1371 if (priv->style == style)
1374 /* Get toggle button and update the state if needed. This will
1375 happen only when the set_style is not invoked from the UI,
1376 for example when it's called from widget memory */
1377 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1378 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1379 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1380 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1381 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1382 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1383 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1386 /* We need to store the selection because it's lost when the
1387 widget is reparented */
1388 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1389 rows = gtk_tree_selection_get_selected_rows (sel, NULL);
1391 priv->style = style;
1393 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1395 if (!priv->wait_for_settings)
1396 modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT (priv->main_paned),
1397 MODEST_CONF_MAIN_PANED_KEY);
1398 /* Remove main paned */
1399 g_object_ref (priv->main_paned);
1400 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1402 /* Reparent the contents widget to the main vbox */
1403 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1406 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1407 /* Remove header view */
1408 g_object_ref (priv->contents_widget);
1409 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1411 /* Reparent the main paned */
1412 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1413 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1415 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
1419 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1421 g_return_if_reached ();
1424 /* Reselect the previously selected folders. We disable the
1425 dimming rules execution during that time because there is
1426 no need to work out it again and it could take a lot of
1427 time if all the headers are selected */
1429 modest_window_disable_dimming (MODEST_WINDOW (self));
1431 gtk_tree_selection_select_path (sel, (GtkTreePath *) list->data);
1432 list = g_list_next (list);
1434 modest_window_enable_dimming (MODEST_WINDOW (self));
1437 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1440 /* Let header view grab the focus if it's being shown */
1441 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1442 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1444 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
1445 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1447 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1450 /* Check dimming rules */
1451 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1452 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1455 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1458 ModestMainWindowStyle
1459 modest_main_window_get_style (ModestMainWindow *self)
1461 ModestMainWindowPrivate *priv;
1463 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1465 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1470 toolbar_resize (ModestMainWindow *self)
1472 ModestMainWindowPrivate *priv = NULL;
1473 ModestWindowPrivate *parent_priv = NULL;
1475 gint static_button_size;
1476 ModestWindowMgr *mgr;
1478 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1479 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1480 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1482 mgr = modest_runtime_get_window_mgr ();
1483 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1485 if (parent_priv->toolbar) {
1486 /* left size buttons */
1487 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1488 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1489 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1490 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1491 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1492 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1493 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1494 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1495 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1496 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1497 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1498 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1499 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1500 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1501 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1502 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1504 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1505 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1506 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1507 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1508 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1509 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1510 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1511 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1519 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1521 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1522 ModestWindowPrivate *parent_priv;
1523 ModestWindowMgr *mgr;
1524 gboolean is_fullscreen;
1525 GtkAction *fs_toggle_action;
1528 mgr = modest_runtime_get_window_mgr ();
1530 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1532 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1534 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1535 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1536 if (is_fullscreen != active) {
1537 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1540 toolbar_resize (MODEST_MAIN_WINDOW (widget));
1548 modest_main_window_show_toolbar (ModestWindow *self,
1549 gboolean show_toolbar)
1551 ModestMainWindowPrivate *priv = NULL;
1552 ModestWindowPrivate *parent_priv = NULL;
1553 GtkWidget *reply_button = NULL, *menu = NULL;
1554 GtkWidget *placeholder = NULL;
1556 const gchar *action_name;
1559 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1560 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1561 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1563 /* Set optimized view status */
1564 priv->optimized_view = !show_toolbar;
1566 if (!parent_priv->toolbar) {
1567 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1569 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1571 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1572 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1573 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1574 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1575 toolbar_resize (MODEST_MAIN_WINDOW (self));
1577 /* Add ProgressBar (Transfer toolbar) */
1578 priv->progress_bar = modest_progress_bar_new ();
1579 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1580 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1581 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1582 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1583 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1585 /* Connect cancel 'clicked' signal to abort progress mode */
1586 g_signal_connect(priv->cancel_toolitem, "clicked",
1587 G_CALLBACK(cancel_progressbar),
1590 /* Add it to the observers list */
1591 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1594 hildon_window_add_toolbar (HILDON_WINDOW (self),
1595 GTK_TOOLBAR (parent_priv->toolbar));
1597 /* Set reply button tap and hold menu */
1598 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1599 "/ToolBar/ToolbarMessageReply");
1600 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1601 "/ToolbarReplyCSM");
1602 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1604 /* Set send & receive button tap and hold menu */
1605 update_menus (MODEST_MAIN_WINDOW (self));
1609 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1610 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1611 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1613 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1614 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1615 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1617 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1619 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1623 /* Update also the actions (to update the toggles in the
1624 menus), we have to do it manually because some other window
1625 of the same time could have changed it (remember that the
1626 toolbar fullscreen mode is shared by all the windows of the
1628 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1629 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1631 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1633 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1634 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1639 on_account_inserted (TnyAccountStore *accoust_store,
1640 TnyAccount *account,
1643 /* Transport accounts and local ones (MMC and the Local
1644 folders account do now cause menu changes */
1645 if (TNY_IS_STORE_ACCOUNT (account) &&
1646 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1648 update_menus (MODEST_MAIN_WINDOW (user_data));
1653 on_default_account_changed (ModestAccountMgr* mgr,
1656 update_menus (MODEST_MAIN_WINDOW (user_data));
1660 on_account_removed (TnyAccountStore *accoust_store,
1661 TnyAccount *account,
1664 /* Transport accounts and local ones (MMC and the Local
1665 folders account do now cause menu changes */
1666 if (TNY_IS_STORE_ACCOUNT (account) &&
1667 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1668 update_menus (MODEST_MAIN_WINDOW (user_data));
1672 on_account_changed (TnyAccountStore *account_store,
1673 TnyAccount *account,
1676 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1678 /* Transport accounts and local ones (MMC and the Local
1679 folders account do now cause menu changes */
1680 if (TNY_IS_STORE_ACCOUNT (account)) {
1681 /* We need to refresh the details widget because it could have changed */
1682 if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1683 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1685 /* Update the menus as well, name could change */
1686 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1687 update_menus (MODEST_MAIN_WINDOW (user_data));
1692 * This function manages the key events used to navigate between
1693 * header and folder views (when the window is in split view)
1696 * -------------------------------------------------
1697 * HeaderView GDK_Left Move focus to folder view
1698 * FolderView GDK_Right Move focus to header view
1700 * There is no need to scroll to selected row, the widgets will be the
1701 * responsibles of doing that (probably managing the focus-in event
1704 on_inner_widgets_key_pressed (GtkWidget *widget,
1708 ModestMainWindowPrivate *priv;
1710 if (event->type == GDK_KEY_RELEASE)
1713 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1715 /* Do nothing if we're in SIMPLE style */
1716 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1719 if (MODEST_IS_HEADER_VIEW (widget)) {
1720 if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left)
1721 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1722 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1723 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1724 if (selected_headers > 1) {
1725 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1728 GtkTreePath * cursor_path;
1729 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1730 if (cursor_path == NULL) {
1731 GtkTreeSelection *selection;
1733 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1734 list = gtk_tree_selection_get_selected_rows (selection, NULL);
1737 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1738 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1743 } else if (MODEST_IS_FOLDER_VIEW (widget) &&
1744 (event->keyval == GDK_Right || event->keyval == GDK_KP_Right || event->keyval == GDK_Left || event->keyval == GDK_KP_Left)) {
1745 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1746 GtkTreePath *selected_path = NULL;
1747 GtkTreePath *start_path = NULL;
1748 GtkTreePath *end_path = NULL;
1750 GtkTreeSelection *selection;
1752 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1753 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1754 if (selected != NULL) {
1755 selected_path = (GtkTreePath *) selected->data;
1756 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1760 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1761 (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1763 /* Scroll to first path */
1764 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1773 gtk_tree_path_free (start_path);
1775 gtk_tree_path_free (end_path);
1776 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1777 g_list_free (selected);
1779 #endif /* GTK_CHECK_VERSION */
1781 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1788 set_alignment (GtkWidget *widget,
1791 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1792 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1796 create_empty_view (void)
1798 GtkLabel *label = NULL;
1799 GtkWidget *align = NULL;
1801 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1802 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1803 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1804 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1806 return GTK_WIDGET(align);
1810 * Free the returned string
1813 get_gray_color_markup (GtkWidget *styled_widget)
1815 gchar *gray_color_markup = NULL;
1816 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1817 /* Obtain the secondary text color. We need a realized widget, that's why
1818 we get styled_widget from outside */
1820 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1821 gray_color_markup = modest_text_utils_get_color_string (&color);
1822 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1824 if (!gray_color_markup)
1825 gray_color_markup = g_strdup ("#BBBBBB");
1827 return gray_color_markup;
1831 * Free the returned string
1834 create_device_name_visual_string (const gchar *device_name,
1835 const gchar *gray_color_markup)
1839 /* We have to use "" to fill the %s of the translation. We can
1840 not just use the device name because the device name is
1841 shown in a different color, so it could not be included
1842 into the <span> tag */
1843 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1844 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1855 GtkWidget *count_label;
1856 GtkWidget *msg_count_label;
1857 GtkWidget *size_label;
1858 gchar *color_markup;
1862 create_uint_label (const gchar *markup,
1866 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", markup, name, count);
1870 create_gchar_label (const gchar *markup,
1874 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", markup, name, count);
1878 update_folder_stats_status_cb (ModestFolderStats stats,
1881 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1884 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_folders"), stats.folders);
1885 gtk_label_set_markup (GTK_LABEL (widgets->count_label), label);
1888 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_messages"), stats.msg_count);
1889 gtk_label_set_markup (GTK_LABEL (widgets->msg_count_label), label);
1892 if (widgets->size_label) {
1893 tmp = modest_text_utils_get_display_size (stats.local_size);
1894 label = create_gchar_label (widgets->color_markup, _("mcen_fi_rootfolder_size"), tmp);
1895 gtk_label_set_markup (GTK_LABEL (widgets->size_label), label);
1902 update_folder_stats_cb (ModestFolderStats stats,
1905 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1908 update_folder_stats_status_cb (stats, user_data);
1910 /* frees. Note that the widgets could have been destroyed but
1911 we still keep a reference */
1912 g_free (widgets->color_markup);
1913 if (widgets->count_label)
1914 g_object_unref (widgets->count_label);
1915 if (widgets->msg_count_label)
1916 g_object_unref (widgets->msg_count_label);
1917 if (widgets->size_label)
1918 g_object_unref (widgets->size_label);
1919 g_slice_free (DetailsWidgets, widgets);
1923 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1925 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1930 gchar *gray_color_markup;
1931 DetailsWidgets *widgets;
1933 vbox = gtk_vbox_new (FALSE, 0);
1934 widgets = g_slice_new0 (DetailsWidgets);
1936 gray_color_markup = get_gray_color_markup (styled_widget);
1937 widgets->color_markup = g_strdup (gray_color_markup);
1939 /* Account description: */
1940 if (modest_tny_account_is_virtual_local_folders (account)
1941 || (modest_tny_account_is_memory_card_account (account))) {
1943 /* Get device name */
1944 gchar *device_name = NULL;
1945 if (modest_tny_account_is_virtual_local_folders (account))
1946 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1947 MODEST_CONF_DEVICE_NAME, NULL);
1949 device_name = g_strdup (tny_account_get_name (account));
1951 label = create_device_name_visual_string ((const gchar *) device_name,
1952 (const gchar *) gray_color_markup);
1953 label_w = gtk_label_new (NULL);
1954 gtk_label_set_markup (GTK_LABEL (label_w), label);
1955 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1956 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1957 g_free (device_name);
1960 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1961 gtk_box_pack_start (GTK_BOX (vbox),
1962 gtk_label_new (tny_account_get_name (account)),
1965 /* Other accounts, such as IMAP and POP: */
1970 /* Put proto in uppercase */
1971 proto = g_string_new (tny_account_get_proto (account));
1972 proto = g_string_ascii_up (proto);
1974 /* note: mcen_fi_localroot_description is something like "%s account"
1975 * however, we should display "%s account: %s"... therefore, ugly tmp */
1976 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1977 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1978 gray_color_markup, tmp, tny_account_get_name (account));
1981 label_w = gtk_label_new (NULL);
1982 gtk_label_set_markup (GTK_LABEL (label_w), label);
1983 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1984 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1985 g_string_free (proto, TRUE);
1991 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1992 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_messages"), 0);
1993 label_w = gtk_label_new (NULL);
1994 gtk_label_set_markup (GTK_LABEL (label_w), label);
1995 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1996 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1999 widgets->msg_count_label = g_object_ref (label_w);
2002 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_folders"), 0);
2003 label_w = gtk_label_new (NULL);
2004 gtk_label_set_markup (GTK_LABEL (label_w), label);
2005 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2006 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2009 widgets->count_label = g_object_ref (label_w);
2012 if (modest_tny_account_is_virtual_local_folders (account)
2013 || modest_tny_account_is_memory_card_account (account)) {
2015 label = create_gchar_label (gray_color_markup, _("mcen_fi_rootfolder_size"), "0");
2017 label_w = gtk_label_new (NULL);
2018 gtk_label_set_markup (GTK_LABEL (label_w), label);
2019 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2020 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2023 widgets->size_label = g_object_ref (label_w);
2025 } else if (TNY_IS_ACCOUNT(folder_store)) {
2026 TnyAccount *account = TNY_ACCOUNT(folder_store);
2028 time_t last_updated;
2029 const gchar *last_updated_string;
2030 /* Get last updated from configuration */
2031 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
2032 tny_account_get_id (account));
2034 #ifdef MODEST_USE_LIBTIME
2035 /* If we use libtime, we are storing the time in UTC so we have to convert to currently
2038 struct tm *localtime_tm;
2040 localtime_tm = localtime (&now);
2041 last_updated -= time_get_utc_offset (localtime_tm->tm_zone);
2044 if (last_updated > 0)
2045 last_updated_string = modest_text_utils_get_display_date(last_updated);
2047 last_updated_string = g_strdup (_("mcen_va_never"));
2049 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
2050 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
2051 label_w = gtk_label_new (NULL);
2052 gtk_label_set_markup (GTK_LABEL (label_w), label);
2053 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2054 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2058 g_free (gray_color_markup);
2060 /* Refresh folder stats asynchronously */
2061 modest_tny_folder_store_get_folder_stats (TNY_FOLDER_STORE (account),
2062 update_folder_stats_cb,
2063 update_folder_stats_status_cb,
2067 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
2073 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
2075 ModestMainWindowPrivate *priv = NULL;
2077 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2079 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2081 return priv->send_receive_in_progress;
2085 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
2087 GtkAction *action = NULL;
2088 GtkWidget *widget = NULL;
2089 ModestMainWindowPrivate *priv = NULL;
2091 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2092 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2094 priv->send_receive_in_progress = TRUE;
2096 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2097 gtk_action_set_sensitive (action, FALSE);
2098 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2099 /* gtk_action_set_sensitive (action, FALSE); */
2100 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2101 gtk_widget_set_sensitive (widget, FALSE);
2105 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
2107 GtkAction *action = NULL;
2108 GtkWidget *widget = NULL;
2109 ModestMainWindowPrivate *priv = NULL;
2111 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2112 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2114 priv->send_receive_in_progress = FALSE;
2116 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2117 gtk_action_set_sensitive (action, TRUE);
2118 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2119 /* gtk_action_set_sensitive (action, TRUE); */
2120 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2121 gtk_widget_set_sensitive (widget, TRUE);
2126 on_msg_count_changed (ModestHeaderView *header_view,
2128 TnyFolderChange *change,
2129 ModestMainWindow *main_window)
2131 gboolean refilter = FALSE;
2132 gboolean folder_empty = FALSE;
2133 gboolean all_marked_as_deleted = FALSE;
2134 ModestMainWindowPrivate *priv;
2136 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
2137 g_return_if_fail (TNY_IS_FOLDER(folder));
2138 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2140 if (change != NULL) {
2141 TnyFolderChangeChanged changed;
2143 changed = tny_folder_change_get_changed (change);
2144 /* If something changes */
2145 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
2146 folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
2148 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2150 /* Play a sound (if configured) and make the LED blink */
2151 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
2152 modest_platform_push_email_notification ();
2155 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
2158 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2161 /* Check if all messages are marked to be deleted */
2162 all_marked_as_deleted = modest_header_view_is_empty (header_view);
2163 folder_empty = folder_empty || all_marked_as_deleted;
2165 /* Set contents style of headers view */
2167 modest_main_window_set_contents_style (main_window,
2168 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2169 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
2171 modest_main_window_set_contents_style (main_window,
2172 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2176 modest_header_view_refilter (header_view);
2181 modest_main_window_set_contents_style (ModestMainWindow *self,
2182 ModestMainWindowContentsStyle style)
2184 ModestMainWindowPrivate *priv;
2186 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2188 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2190 /* We allow to set the same content style than the previously
2191 set if there are details, because it could happen when we're
2192 selecting different accounts consecutively */
2193 if ((priv->contents_style == style) &&
2194 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
2197 /* Remove previous child. Delete it if it was an account
2199 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
2201 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
2202 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
2205 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
2208 priv->contents_style = style;
2210 switch (priv->contents_style) {
2211 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
2212 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
2213 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2215 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2216 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
2218 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
2220 /* if we're started without main win, there may not be a folder
2221 * view. this fixes a GLib-Critical */
2222 if (priv->folder_view) {
2223 TnyFolderStore *selected_folderstore =
2224 modest_folder_view_get_selected (priv->folder_view);
2225 if (TNY_IS_ACCOUNT (selected_folderstore)) {
2226 priv->details_widget = create_details_widget (GTK_WIDGET (self),
2227 TNY_ACCOUNT (selected_folderstore));
2229 wrap_in_scrolled_window (priv->contents_widget,
2230 priv->details_widget);
2232 if (selected_folderstore)
2233 g_object_unref (selected_folderstore);
2234 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2237 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2238 gtk_widget_grab_focus (GTK_WIDGET (priv->details_widget));
2241 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
2242 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
2243 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2245 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2246 gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
2249 g_return_if_reached ();
2253 gtk_widget_show_all (priv->contents_widget);
2255 /* Recompute dimming rules */
2256 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2257 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2260 ModestMainWindowContentsStyle
2261 modest_main_window_get_contents_style (ModestMainWindow *self)
2263 ModestMainWindowPrivate *priv;
2265 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
2267 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2268 return priv->contents_style;
2273 on_configuration_key_changed (ModestConf* conf,
2275 ModestConfEvent event,
2276 ModestConfNotificationId id,
2277 ModestMainWindow *self)
2279 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2280 TnyAccount *account = NULL;
2282 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
2285 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
2288 if (priv->folder_view)
2289 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
2291 if (account && TNY_IS_ACCOUNT (account) &&
2292 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
2295 const gchar *device_name;
2296 gchar *new_text, *gray_color_markup;
2299 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
2300 label = GTK_LABEL (children->data);
2302 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2303 MODEST_CONF_DEVICE_NAME, NULL);
2305 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
2306 new_text = create_device_name_visual_string (device_name, gray_color_markup);
2308 gtk_label_set_markup (label, new_text);
2309 gtk_widget_show (GTK_WIDGET (label));
2311 g_free (gray_color_markup);
2313 g_list_free (children);
2315 g_object_unref (account);
2319 set_toolbar_transfer_mode (ModestMainWindow *self)
2321 ModestMainWindowPrivate *priv = NULL;
2323 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2325 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2327 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2329 if (priv->progress_bar_timeout > 0) {
2330 g_source_remove (priv->progress_bar_timeout);
2331 priv->progress_bar_timeout = 0;
2338 set_toolbar_mode (ModestMainWindow *self,
2339 ModestToolBarModes mode)
2341 ModestWindowPrivate *parent_priv = NULL;
2342 ModestMainWindowPrivate *priv = NULL;
2343 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2345 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2347 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2348 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2350 /* In case this was called before the toolbar exists: */
2351 if (!(parent_priv->toolbar))
2354 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2356 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2357 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2358 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2360 /* Sets current toolbar mode */
2361 priv->current_toolbar_mode = mode;
2363 /* Checks the dimming rules */
2364 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2365 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2367 /* Show and hide toolbar items */
2369 case TOOLBAR_MODE_NORMAL:
2371 gtk_action_set_visible (sort_action, TRUE);
2373 gtk_action_set_visible (refresh_action, TRUE);
2374 if (priv->progress_toolitem) {
2375 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2376 gtk_widget_hide (priv->progress_toolitem);
2378 if (priv->progress_bar)
2379 gtk_widget_hide (priv->progress_bar);
2382 gtk_action_set_visible (cancel_action, FALSE);
2384 /* Hide toolbar if optimized view is enabled */
2385 if (priv->optimized_view)
2386 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2388 case TOOLBAR_MODE_TRANSFER:
2390 gtk_action_set_visible (sort_action, FALSE);
2392 gtk_action_set_visible (refresh_action, FALSE);
2394 gtk_action_set_visible (cancel_action, TRUE);
2395 if (priv->progress_bar)
2396 gtk_widget_show (priv->progress_bar);
2397 if (priv->progress_toolitem) {
2398 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2399 gtk_widget_show (priv->progress_toolitem);
2402 /* Show toolbar if it's hiden (optimized view ) */
2403 if (priv->optimized_view)
2404 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2407 g_return_if_reached ();
2412 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2414 ModestMainWindowPrivate *priv;
2416 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2417 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2419 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2423 cancel_progressbar (GtkToolButton *toolbutton,
2424 ModestMainWindow *self)
2427 ModestMainWindowPrivate *priv;
2429 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2431 /* Get operation observers and cancel all the operations */
2432 tmp = priv->progress_widgets;
2434 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2435 tmp=g_slist_next(tmp);
2440 observers_empty (ModestMainWindow *self)
2443 ModestMainWindowPrivate *priv;
2444 gboolean is_empty = TRUE;
2445 guint pending_ops = 0;
2447 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2448 tmp = priv->progress_widgets;
2450 /* Check all observers */
2451 while (tmp && is_empty) {
2452 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2453 is_empty = pending_ops == 0;
2455 tmp = g_slist_next(tmp);
2463 * Gets the toolbar mode needed for each mail operation. It stores in
2464 * @mode_changed if the toolbar mode has changed or not
2466 static ModestToolBarModes
2467 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2468 ModestMailOperation *mail_op,
2469 gboolean *mode_changed)
2471 ModestToolBarModes mode;
2472 ModestMainWindowPrivate *priv;
2474 *mode_changed = FALSE;
2475 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2477 /* Get toolbar mode from operation id*/
2478 switch (modest_mail_operation_get_type_operation (mail_op)) {
2479 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
2480 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2481 mode = TOOLBAR_MODE_TRANSFER;
2482 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2483 *mode_changed = TRUE;
2486 mode = TOOLBAR_MODE_NORMAL;
2492 on_mail_operation_started (ModestMailOperation *mail_op,
2495 ModestMainWindow *self;
2496 ModestMailOperationTypeOperation op_type;
2497 ModestMainWindowPrivate *priv;
2498 ModestToolBarModes mode;
2500 gboolean mode_changed = FALSE;
2501 TnyAccount *account = NULL;
2503 self = MODEST_MAIN_WINDOW (user_data);
2504 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2506 /* Do not show progress for receiving operations if the
2507 account is the local account or the MMC one */
2508 op_type = modest_mail_operation_get_type_operation (mail_op);
2509 account = modest_mail_operation_get_account (mail_op);
2510 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2513 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2514 modest_tny_account_is_memory_card_account (account));
2516 g_object_unref (account);
2520 /* Show information banner. Remove old timeout */
2521 if (priv->opening_banner_timeout > 0) {
2522 g_source_remove (priv->opening_banner_timeout);
2523 priv->opening_banner_timeout = 0;
2525 /* Create a new timeout */
2526 priv->opening_banner_timeout =
2527 g_timeout_add (2000, show_opening_banner, self);
2530 /* Not every mail operation has account, noop does not */
2532 g_object_unref (account);
2534 /* Get toolbar mode from operation id*/
2535 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2537 /* Add operation observers and change toolbar if neccessary*/
2538 tmp = priv->progress_widgets;
2539 if (mode == TOOLBAR_MODE_TRANSFER) {
2541 GObject *source = modest_mail_operation_get_source(mail_op);
2542 if (G_OBJECT (self) == source) {
2543 set_toolbar_transfer_mode(self);
2545 g_object_unref (source);
2549 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2551 tmp = g_slist_next (tmp);
2555 /* Update the main menu as well, we need to explicitely do
2556 this in order to enable/disable accelerators */
2557 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2561 on_mail_operation_finished (ModestMailOperation *mail_op,
2564 ModestToolBarModes mode;
2565 ModestMailOperationTypeOperation op_type;
2567 ModestMainWindow *self;
2568 gboolean mode_changed;
2569 TnyAccount *account = NULL;
2570 ModestMainWindowPrivate *priv;
2572 self = MODEST_MAIN_WINDOW (user_data);
2573 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2575 /* The mail operation was not added to the progress objects if
2576 the account was the local account or the MMC one */
2577 op_type = modest_mail_operation_get_type_operation (mail_op);
2578 account = modest_mail_operation_get_account (mail_op);
2579 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2582 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2583 modest_tny_account_is_memory_card_account (account));
2585 g_object_unref (account);
2589 /* Remove old timeout */
2590 if (priv->opening_banner_timeout > 0) {
2591 g_source_remove (priv->opening_banner_timeout);
2592 priv->opening_banner_timeout = 0;
2595 /* Remove the banner if exists */
2596 if (priv->opening_banner) {
2597 gtk_widget_destroy (priv->opening_banner);
2598 priv->opening_banner = NULL;
2602 /* Not every mail operation has account, noop does not */
2604 g_object_unref (account);
2606 /* Get toolbar mode from operation id*/
2607 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2609 /* Change toolbar mode */
2610 tmp = priv->progress_widgets;
2611 if (mode == TOOLBAR_MODE_TRANSFER) {
2613 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2615 tmp = g_slist_next (tmp);
2618 /* If no more operations are being observed, NORMAL mode is enabled again */
2619 if (observers_empty (self)) {
2620 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2626 on_queue_changed (ModestMailOperationQueue *queue,
2627 ModestMailOperation *mail_op,
2628 ModestMailOperationQueueNotification type,
2629 ModestMainWindow *self)
2631 ModestMainWindowPrivate *priv;
2633 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2635 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2636 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2638 "operation-started",
2639 G_CALLBACK (on_mail_operation_started),
2641 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2643 "operation-finished",
2644 G_CALLBACK (on_mail_operation_finished),
2646 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2647 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2649 "operation-started");
2650 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2652 "operation-finished");
2657 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2659 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2661 ModestAccountMgr *mgr;
2662 ModestAccountSettings *settings;
2663 ModestServerAccountSettings *store_settings = NULL;
2665 /* Get account data */
2666 mgr = modest_runtime_get_account_mgr ();
2667 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2669 store_settings = modest_account_settings_get_store_settings (settings);
2671 /* Set the new visible & active account */
2672 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2673 const gchar *account_name;
2675 account_name = modest_account_settings_get_account_name (settings);
2677 modest_folder_view_set_account_id_of_visible_server_account
2679 modest_server_account_settings_get_account_name (store_settings));
2680 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2681 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2683 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2684 if (action != NULL) {
2685 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2686 modest_utils_toggle_action_set_active_block_notify (
2687 GTK_TOGGLE_ACTION (action),
2695 g_object_unref (store_settings);
2696 g_object_unref (settings);
2700 /* Make sure that at least one account is "viewed": */
2702 set_at_least_one_account_visible(ModestMainWindow *self)
2704 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2705 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2707 if (!(priv->folder_view)) {
2708 /* It is too early to do this. */
2712 const gchar *active_server_account_name =
2713 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2715 if (!active_server_account_name ||
2716 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2718 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2719 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2720 if (default_modest_name) {
2721 set_account_visible (self, default_modest_name);
2722 } else if (first_modest_name) {
2723 set_account_visible (self, first_modest_name);
2725 g_free (first_modest_name);
2726 g_free (default_modest_name);
2731 on_show_account_action_toggled (GtkToggleAction *action,
2734 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2736 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2737 if (gtk_toggle_action_get_active (action))
2738 set_account_visible (self, acc_name);
2742 refresh_account (const gchar *account_name)
2746 /* win must already exists here, obviously */
2747 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2750 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2754 /* If account_name == NULL, we must update all (option All) */
2756 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2758 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2763 on_refresh_account_action_activated (GtkAction *action,
2766 refresh_account ((const gchar*) user_data);
2770 on_send_receive_csm_activated (GtkMenuItem *item,
2773 refresh_account ((const gchar*) user_data);
2777 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2779 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2781 hildon_banner_show_information (NULL, NULL,
2782 _CS("ckct_ib_cannot_zoom_here"));
2788 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2790 ModestMainWindow *main_window = NULL;
2792 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2793 main_window = MODEST_MAIN_WINDOW (userdata);
2795 /* Update toolbar dimming state */
2796 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2797 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2803 on_header_view_focus_in (GtkWidget *widget,
2804 GdkEventFocus *event,
2807 ModestMainWindow *main_window = NULL;
2809 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2811 main_window = MODEST_MAIN_WINDOW (userdata);
2813 /* Update toolbar dimming state */
2814 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2815 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2821 on_folder_selection_changed (ModestFolderView *folder_view,
2822 TnyFolderStore *folder_store,
2824 ModestMainWindow *main_window)
2826 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2827 GtkAction *action = NULL;
2828 gboolean show_reply = TRUE;
2829 gboolean show_forward = TRUE;
2830 gboolean show_cancel_send = FALSE;
2831 gboolean show_clipboard = TRUE;
2832 gboolean show_delete = TRUE;
2835 if (TNY_IS_ACCOUNT (folder_store)) {
2836 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2837 } else if (TNY_IS_FOLDER (folder_store)) {
2838 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2839 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2840 TNY_FOLDER (folder_store));
2841 switch (folder_type) {
2842 case TNY_FOLDER_TYPE_DRAFTS:
2843 show_clipboard = show_delete = TRUE;
2844 show_reply = show_forward = show_cancel_send = FALSE;
2846 case TNY_FOLDER_TYPE_SENT:
2847 show_forward = show_clipboard = show_delete = TRUE;
2848 show_reply = show_cancel_send = FALSE;
2850 case TNY_FOLDER_TYPE_OUTBOX:
2851 show_clipboard = show_delete = show_cancel_send = TRUE;
2852 show_reply = show_forward = FALSE;
2854 case TNY_FOLDER_TYPE_INVALID:
2855 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2858 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2859 show_cancel_send = FALSE;
2862 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2863 show_cancel_send = FALSE;
2868 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2869 gtk_action_set_visible (action, show_reply);
2870 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2871 gtk_action_set_visible (action, show_reply);
2872 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2873 gtk_action_set_visible (action, show_forward);
2874 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2875 gtk_action_set_visible (action, show_cancel_send);
2876 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2877 gtk_action_set_visible (action, show_delete);
2879 /* We finally call to the ui actions handler, after updating properly
2880 * the header view CSM */
2881 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2885 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2886 GtkTreeModel *model,
2887 GtkTreeRowReference *row_reference,
2888 ModestMainWindow *self)
2890 ModestMainWindowPrivate *priv = NULL;
2891 GtkTreeModel *header_model = NULL;
2892 GtkTreePath *path = NULL;
2894 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2895 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2896 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2898 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2899 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2901 /* Do nothing if we changed the folder in the main view */
2902 if (header_model != model)
2905 /* Select the message in the header view */
2906 path = gtk_tree_row_reference_get_path (row_reference);
2907 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2909 gtk_tree_path_free (path);
2915 updating_banner_destroyed (gpointer data,
2916 GObject *where_the_object_was)
2918 ModestMainWindowPrivate *priv = NULL;
2920 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2922 priv->updating_banner = NULL;
2926 show_updating_banner (gpointer user_data)
2928 ModestMainWindowPrivate *priv = NULL;
2930 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2932 if (priv->updating_banner == NULL) {
2934 /* We're outside the main lock */
2935 gdk_threads_enter ();
2936 priv->updating_banner =
2937 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2938 _CS ("ckdg_pb_updating"));
2940 /* We need this because banners in Maemo could be
2941 destroyed by dialogs so we need to properly update
2942 our reference to it */
2943 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2944 updating_banner_destroyed,
2946 gdk_threads_leave ();
2949 /* Remove timeout */
2950 priv->updating_banner_timeout = 0;
2955 * We use this function to show/hide a progress banner showing
2956 * "Updating" while the header view is being filled. We're not showing
2957 * it unless the update takes more than 2 seconds
2959 * If starting = TRUE then the refresh is starting, otherwise it means
2960 * that is has just finished
2963 on_updating_msg_list (ModestHeaderView *header_view,
2967 ModestMainWindowPrivate *priv = NULL;
2969 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2971 /* Remove old timeout */
2972 if (priv->updating_banner_timeout > 0) {
2973 g_source_remove (priv->updating_banner_timeout);
2974 priv->updating_banner_timeout = 0;
2977 /* Create a new timeout */
2979 priv->updating_banner_timeout =
2980 g_timeout_add (2000, show_updating_banner, user_data);
2982 /* Remove the banner if exists */
2983 if (priv->updating_banner) {
2984 gtk_widget_destroy (priv->updating_banner);
2985 priv->updating_banner = NULL;
2991 modest_main_window_screen_is_on (ModestMainWindow *self)
2993 ModestMainWindowPrivate *priv = NULL;
2995 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2997 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2999 return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
3003 remove_banners (ModestMainWindow *window)
3005 ModestMainWindowPrivate *priv;
3007 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
3009 if (priv->opening_banner_timeout > 0) {
3010 g_source_remove (priv->opening_banner_timeout);
3011 priv->opening_banner_timeout = 0;
3014 if (priv->opening_banner != NULL) {
3015 gtk_widget_destroy (priv->opening_banner);
3016 priv->opening_banner = NULL;
3019 if (priv->updating_banner_timeout > 0) {
3020 g_source_remove (priv->updating_banner_timeout);
3021 priv->updating_banner_timeout = 0;
3024 if (priv->updating_banner != NULL) {
3025 gtk_widget_destroy (priv->updating_banner);
3026 priv->updating_banner = NULL;
3032 on_window_hide (GObject *gobject,
3036 g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
3038 if (!GTK_WIDGET_VISIBLE (gobject)) {
3039 TnyFolderStore *folder_store;
3040 ModestMainWindowPrivate *priv;
3042 /* Remove the currently shown banners */
3043 remove_banners (MODEST_MAIN_WINDOW (gobject));
3045 /* Force the folder view to sync the currently selected folder
3046 to save the read/unread status and to expunge messages */
3047 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
3048 folder_store = modest_folder_view_get_selected (priv->folder_view);
3049 if (TNY_IS_FOLDER (folder_store)) {
3050 ModestMailOperation *mail_op;
3052 mail_op = modest_mail_operation_new (NULL);
3053 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3055 modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
3056 g_object_unref (mail_op);
3057 g_object_unref (folder_store);
3063 on_window_destroy (GtkObject *widget,
3066 g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
3068 remove_banners (MODEST_MAIN_WINDOW (widget));
3072 opening_banner_destroyed (gpointer data,
3073 GObject *where_the_object_was)
3075 ModestMainWindowPrivate *priv = NULL;
3077 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
3079 priv->opening_banner = NULL;
3083 show_opening_banner (gpointer user_data)
3085 ModestMainWindowPrivate *priv = NULL;
3087 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
3089 if (priv->opening_banner == NULL) {
3091 /* We're outside the main lock */
3092 gdk_threads_enter ();
3093 priv->opening_banner =
3094 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
3095 _("mail_me_opening"));
3097 /* We need this because banners in Maemo could be
3098 destroyed by dialogs so we need to properly update
3099 our reference to it */
3100 g_object_weak_ref (G_OBJECT (priv->opening_banner),
3101 opening_banner_destroyed,
3104 /* We need this because banners in Maemo could be
3105 destroyed by dialogs so we need to properly update
3106 our reference to it */
3107 g_object_weak_ref (G_OBJECT (priv->updating_banner),
3108 updating_banner_destroyed,
3110 gdk_threads_leave ();
3113 /* Remove timeout */
3114 priv->opening_banner_timeout = 0;