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 /* Obtain the secondary text color. We need a realized widget, that's why
1817 we get styled_widget from outside */
1819 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1820 gray_color_markup = modest_text_utils_get_color_string (&color);
1822 if (!gray_color_markup)
1823 gray_color_markup = g_strdup ("#BBBBBB");
1825 return gray_color_markup;
1829 * Free the returned string
1832 create_device_name_visual_string (const gchar *device_name,
1833 const gchar *gray_color_markup)
1837 /* We have to use "" to fill the %s of the translation. We can
1838 not just use the device name because the device name is
1839 shown in a different color, so it could not be included
1840 into the <span> tag */
1841 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1842 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1853 GtkWidget *count_label;
1854 GtkWidget *msg_count_label;
1855 GtkWidget *size_label;
1856 gchar *color_markup;
1860 create_uint_label (const gchar *markup,
1864 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", markup, name, count);
1868 create_gchar_label (const gchar *markup,
1872 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", markup, name, count);
1876 update_folder_stats_status_cb (ModestFolderStats stats,
1879 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1882 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_folders"), stats.folders);
1883 gtk_label_set_markup (GTK_LABEL (widgets->count_label), label);
1886 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_messages"), stats.msg_count);
1887 gtk_label_set_markup (GTK_LABEL (widgets->msg_count_label), label);
1890 if (widgets->size_label) {
1891 tmp = modest_text_utils_get_display_size (stats.local_size);
1892 label = create_gchar_label (widgets->color_markup, _("mcen_fi_rootfolder_size"), tmp);
1893 gtk_label_set_markup (GTK_LABEL (widgets->size_label), label);
1900 update_folder_stats_cb (ModestFolderStats stats,
1903 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1906 update_folder_stats_status_cb (stats, user_data);
1908 /* frees. Note that the widgets could have been destroyed but
1909 we still keep a reference */
1910 g_free (widgets->color_markup);
1911 if (widgets->count_label)
1912 g_object_unref (widgets->count_label);
1913 if (widgets->msg_count_label)
1914 g_object_unref (widgets->msg_count_label);
1915 if (widgets->size_label)
1916 g_object_unref (widgets->size_label);
1917 g_slice_free (DetailsWidgets, widgets);
1921 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1923 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1928 gchar *gray_color_markup;
1929 DetailsWidgets *widgets;
1931 vbox = gtk_vbox_new (FALSE, 0);
1932 widgets = g_slice_new0 (DetailsWidgets);
1934 gray_color_markup = get_gray_color_markup (styled_widget);
1935 widgets->color_markup = g_strdup (gray_color_markup);
1937 /* Account description: */
1938 if (modest_tny_account_is_virtual_local_folders (account)
1939 || (modest_tny_account_is_memory_card_account (account))) {
1941 /* Get device name */
1942 gchar *device_name = NULL;
1943 if (modest_tny_account_is_virtual_local_folders (account))
1944 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1945 MODEST_CONF_DEVICE_NAME, NULL);
1947 device_name = g_strdup (tny_account_get_name (account));
1949 label = create_device_name_visual_string ((const gchar *) device_name,
1950 (const gchar *) gray_color_markup);
1951 label_w = gtk_label_new (NULL);
1952 gtk_label_set_markup (GTK_LABEL (label_w), label);
1953 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1954 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1955 g_free (device_name);
1958 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1959 gtk_box_pack_start (GTK_BOX (vbox),
1960 gtk_label_new (tny_account_get_name (account)),
1963 /* Other accounts, such as IMAP and POP: */
1968 /* Put proto in uppercase */
1969 proto = g_string_new (tny_account_get_proto (account));
1970 proto = g_string_ascii_up (proto);
1972 /* note: mcen_fi_localroot_description is something like "%s account"
1973 * however, we should display "%s account: %s"... therefore, ugly tmp */
1974 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1975 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1976 gray_color_markup, tmp, tny_account_get_name (account));
1979 label_w = gtk_label_new (NULL);
1980 gtk_label_set_markup (GTK_LABEL (label_w), label);
1981 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1982 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1983 g_string_free (proto, TRUE);
1989 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1990 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_messages"), 0);
1991 label_w = gtk_label_new (NULL);
1992 gtk_label_set_markup (GTK_LABEL (label_w), label);
1993 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1994 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1997 widgets->msg_count_label = g_object_ref (label_w);
2000 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_folders"), 0);
2001 label_w = gtk_label_new (NULL);
2002 gtk_label_set_markup (GTK_LABEL (label_w), label);
2003 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2004 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2007 widgets->count_label = g_object_ref (label_w);
2010 if (modest_tny_account_is_virtual_local_folders (account)
2011 || modest_tny_account_is_memory_card_account (account)) {
2013 label = create_gchar_label (gray_color_markup, _("mcen_fi_rootfolder_size"), "0");
2015 label_w = gtk_label_new (NULL);
2016 gtk_label_set_markup (GTK_LABEL (label_w), label);
2017 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2018 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2021 widgets->size_label = g_object_ref (label_w);
2023 } else if (TNY_IS_ACCOUNT(folder_store)) {
2024 TnyAccount *account = TNY_ACCOUNT(folder_store);
2026 time_t last_updated;
2027 const gchar *last_updated_string;
2028 /* Get last updated from configuration */
2029 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
2030 tny_account_get_id (account));
2032 #ifdef MODEST_USE_LIBTIME
2033 /* If we use libtime, we are storing the time in UTC so we have to convert to currently
2036 struct tm *localtime_tm;
2038 localtime_tm = localtime (&now);
2039 last_updated -= time_get_utc_offset (localtime_tm->tm_zone);
2042 if (last_updated > 0)
2043 last_updated_string = modest_text_utils_get_display_date(last_updated);
2045 last_updated_string = g_strdup (_("mcen_va_never"));
2047 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
2048 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
2049 label_w = gtk_label_new (NULL);
2050 gtk_label_set_markup (GTK_LABEL (label_w), label);
2051 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2052 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2056 g_free (gray_color_markup);
2058 /* Refresh folder stats asynchronously */
2059 modest_tny_folder_store_get_folder_stats (TNY_FOLDER_STORE (account),
2060 update_folder_stats_cb,
2061 update_folder_stats_status_cb,
2065 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
2071 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
2073 ModestMainWindowPrivate *priv = NULL;
2075 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2077 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2079 return priv->send_receive_in_progress;
2083 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
2085 GtkAction *action = NULL;
2086 GtkWidget *widget = NULL;
2087 ModestMainWindowPrivate *priv = NULL;
2089 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2090 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2092 priv->send_receive_in_progress = TRUE;
2094 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2095 gtk_action_set_sensitive (action, FALSE);
2096 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2097 /* gtk_action_set_sensitive (action, FALSE); */
2098 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2099 gtk_widget_set_sensitive (widget, FALSE);
2103 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
2105 GtkAction *action = NULL;
2106 GtkWidget *widget = NULL;
2107 ModestMainWindowPrivate *priv = NULL;
2109 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2110 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2112 priv->send_receive_in_progress = FALSE;
2114 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2115 gtk_action_set_sensitive (action, TRUE);
2116 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2117 /* gtk_action_set_sensitive (action, TRUE); */
2118 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2119 gtk_widget_set_sensitive (widget, TRUE);
2124 on_msg_count_changed (ModestHeaderView *header_view,
2126 TnyFolderChange *change,
2127 ModestMainWindow *main_window)
2129 gboolean refilter = FALSE;
2130 gboolean folder_empty = FALSE;
2131 gboolean all_marked_as_deleted = FALSE;
2132 ModestMainWindowPrivate *priv;
2134 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
2135 g_return_if_fail (TNY_IS_FOLDER(folder));
2136 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2138 if (change != NULL) {
2139 TnyFolderChangeChanged changed;
2141 changed = tny_folder_change_get_changed (change);
2142 /* If something changes */
2143 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
2144 folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
2146 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2148 /* Play a sound (if configured) and make the LED blink */
2149 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
2150 modest_platform_push_email_notification ();
2153 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
2156 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2159 /* Check if all messages are marked to be deleted */
2160 all_marked_as_deleted = modest_header_view_is_empty (header_view);
2161 folder_empty = folder_empty || all_marked_as_deleted;
2163 /* Set contents style of headers view */
2165 modest_main_window_set_contents_style (main_window,
2166 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2167 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
2169 modest_main_window_set_contents_style (main_window,
2170 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2174 modest_header_view_refilter (header_view);
2179 modest_main_window_set_contents_style (ModestMainWindow *self,
2180 ModestMainWindowContentsStyle style)
2182 ModestMainWindowPrivate *priv;
2184 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2186 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2188 /* We allow to set the same content style than the previously
2189 set if there are details, because it could happen when we're
2190 selecting different accounts consecutively */
2191 if ((priv->contents_style == style) &&
2192 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
2195 /* Remove previous child. Delete it if it was an account
2197 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
2199 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
2200 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
2203 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
2206 priv->contents_style = style;
2208 switch (priv->contents_style) {
2209 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
2210 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
2211 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2213 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2214 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
2216 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
2218 /* if we're started without main win, there may not be a folder
2219 * view. this fixes a GLib-Critical */
2220 if (priv->folder_view) {
2221 TnyFolderStore *selected_folderstore =
2222 modest_folder_view_get_selected (priv->folder_view);
2223 if (TNY_IS_ACCOUNT (selected_folderstore)) {
2224 priv->details_widget = create_details_widget (GTK_WIDGET (self),
2225 TNY_ACCOUNT (selected_folderstore));
2227 wrap_in_scrolled_window (priv->contents_widget,
2228 priv->details_widget);
2230 if (selected_folderstore)
2231 g_object_unref (selected_folderstore);
2232 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2235 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2236 gtk_widget_grab_focus (GTK_WIDGET (priv->details_widget));
2239 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
2240 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
2241 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2243 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2244 gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
2247 g_return_if_reached ();
2251 gtk_widget_show_all (priv->contents_widget);
2253 /* Recompute dimming rules */
2254 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2255 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2258 ModestMainWindowContentsStyle
2259 modest_main_window_get_contents_style (ModestMainWindow *self)
2261 ModestMainWindowPrivate *priv;
2263 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
2265 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2266 return priv->contents_style;
2271 on_configuration_key_changed (ModestConf* conf,
2273 ModestConfEvent event,
2274 ModestConfNotificationId id,
2275 ModestMainWindow *self)
2277 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2278 TnyAccount *account = NULL;
2280 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
2283 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
2286 if (priv->folder_view)
2287 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
2289 if (account && TNY_IS_ACCOUNT (account) &&
2290 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
2293 const gchar *device_name;
2294 gchar *new_text, *gray_color_markup;
2297 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
2298 label = GTK_LABEL (children->data);
2300 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2301 MODEST_CONF_DEVICE_NAME, NULL);
2303 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
2304 new_text = create_device_name_visual_string (device_name, gray_color_markup);
2306 gtk_label_set_markup (label, new_text);
2307 gtk_widget_show (GTK_WIDGET (label));
2309 g_free (gray_color_markup);
2311 g_list_free (children);
2313 g_object_unref (account);
2317 set_toolbar_transfer_mode (ModestMainWindow *self)
2319 ModestMainWindowPrivate *priv = NULL;
2321 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2323 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2325 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2327 if (priv->progress_bar_timeout > 0) {
2328 g_source_remove (priv->progress_bar_timeout);
2329 priv->progress_bar_timeout = 0;
2336 set_toolbar_mode (ModestMainWindow *self,
2337 ModestToolBarModes mode)
2339 ModestWindowPrivate *parent_priv = NULL;
2340 ModestMainWindowPrivate *priv = NULL;
2341 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2343 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2345 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2346 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2348 /* In case this was called before the toolbar exists: */
2349 if (!(parent_priv->toolbar))
2352 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2354 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2355 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2356 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2358 /* Sets current toolbar mode */
2359 priv->current_toolbar_mode = mode;
2361 /* Checks the dimming rules */
2362 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2363 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2365 /* Show and hide toolbar items */
2367 case TOOLBAR_MODE_NORMAL:
2369 gtk_action_set_visible (sort_action, TRUE);
2371 gtk_action_set_visible (refresh_action, TRUE);
2372 if (priv->progress_toolitem) {
2373 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2374 gtk_widget_hide (priv->progress_toolitem);
2376 if (priv->progress_bar)
2377 gtk_widget_hide (priv->progress_bar);
2380 gtk_action_set_visible (cancel_action, FALSE);
2382 /* Hide toolbar if optimized view is enabled */
2383 if (priv->optimized_view)
2384 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2386 case TOOLBAR_MODE_TRANSFER:
2388 gtk_action_set_visible (sort_action, FALSE);
2390 gtk_action_set_visible (refresh_action, FALSE);
2392 gtk_action_set_visible (cancel_action, TRUE);
2393 if (priv->progress_bar)
2394 gtk_widget_show (priv->progress_bar);
2395 if (priv->progress_toolitem) {
2396 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2397 gtk_widget_show (priv->progress_toolitem);
2400 /* Show toolbar if it's hiden (optimized view ) */
2401 if (priv->optimized_view)
2402 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2405 g_return_if_reached ();
2410 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2412 ModestMainWindowPrivate *priv;
2414 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2415 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2417 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2421 cancel_progressbar (GtkToolButton *toolbutton,
2422 ModestMainWindow *self)
2425 ModestMainWindowPrivate *priv;
2427 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2429 /* Get operation observers and cancel all the operations */
2430 tmp = priv->progress_widgets;
2432 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2433 tmp=g_slist_next(tmp);
2438 observers_empty (ModestMainWindow *self)
2441 ModestMainWindowPrivate *priv;
2442 gboolean is_empty = TRUE;
2443 guint pending_ops = 0;
2445 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2446 tmp = priv->progress_widgets;
2448 /* Check all observers */
2449 while (tmp && is_empty) {
2450 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2451 is_empty = pending_ops == 0;
2453 tmp = g_slist_next(tmp);
2461 * Gets the toolbar mode needed for each mail operation. It stores in
2462 * @mode_changed if the toolbar mode has changed or not
2464 static ModestToolBarModes
2465 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2466 ModestMailOperation *mail_op,
2467 gboolean *mode_changed)
2469 ModestToolBarModes mode;
2470 ModestMainWindowPrivate *priv;
2472 *mode_changed = FALSE;
2473 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2475 /* Get toolbar mode from operation id*/
2476 switch (modest_mail_operation_get_type_operation (mail_op)) {
2477 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
2478 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2479 mode = TOOLBAR_MODE_TRANSFER;
2480 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2481 *mode_changed = TRUE;
2484 mode = TOOLBAR_MODE_NORMAL;
2490 on_mail_operation_started (ModestMailOperation *mail_op,
2493 ModestMainWindow *self;
2494 ModestMailOperationTypeOperation op_type;
2495 ModestMainWindowPrivate *priv;
2496 ModestToolBarModes mode;
2498 gboolean mode_changed = FALSE;
2499 TnyAccount *account = NULL;
2501 self = MODEST_MAIN_WINDOW (user_data);
2502 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2504 /* Do not show progress for receiving operations if the
2505 account is the local account or the MMC one */
2506 op_type = modest_mail_operation_get_type_operation (mail_op);
2507 account = modest_mail_operation_get_account (mail_op);
2508 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2511 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2512 modest_tny_account_is_memory_card_account (account));
2514 g_object_unref (account);
2518 /* Show information banner. Remove old timeout */
2519 if (priv->opening_banner_timeout > 0) {
2520 g_source_remove (priv->opening_banner_timeout);
2521 priv->opening_banner_timeout = 0;
2523 /* Create a new timeout */
2524 priv->opening_banner_timeout =
2525 g_timeout_add (2000, show_opening_banner, self);
2528 /* Not every mail operation has account, noop does not */
2530 g_object_unref (account);
2532 /* Get toolbar mode from operation id*/
2533 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2535 /* Add operation observers and change toolbar if neccessary*/
2536 tmp = priv->progress_widgets;
2537 if (mode == TOOLBAR_MODE_TRANSFER) {
2539 GObject *source = modest_mail_operation_get_source(mail_op);
2540 if (G_OBJECT (self) == source) {
2541 set_toolbar_transfer_mode(self);
2543 g_object_unref (source);
2547 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2549 tmp = g_slist_next (tmp);
2553 /* Update the main menu as well, we need to explicitely do
2554 this in order to enable/disable accelerators */
2555 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2559 on_mail_operation_finished (ModestMailOperation *mail_op,
2562 ModestToolBarModes mode;
2563 ModestMailOperationTypeOperation op_type;
2565 ModestMainWindow *self;
2566 gboolean mode_changed;
2567 TnyAccount *account = NULL;
2568 ModestMainWindowPrivate *priv;
2570 self = MODEST_MAIN_WINDOW (user_data);
2571 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2573 /* The mail operation was not added to the progress objects if
2574 the account was the local account or the MMC one */
2575 op_type = modest_mail_operation_get_type_operation (mail_op);
2576 account = modest_mail_operation_get_account (mail_op);
2577 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2580 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2581 modest_tny_account_is_memory_card_account (account));
2583 g_object_unref (account);
2587 /* Remove old timeout */
2588 if (priv->opening_banner_timeout > 0) {
2589 g_source_remove (priv->opening_banner_timeout);
2590 priv->opening_banner_timeout = 0;
2593 /* Remove the banner if exists */
2594 if (priv->opening_banner) {
2595 gtk_widget_destroy (priv->opening_banner);
2596 priv->opening_banner = NULL;
2600 /* Not every mail operation has account, noop does not */
2602 g_object_unref (account);
2604 /* Get toolbar mode from operation id*/
2605 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2607 /* Change toolbar mode */
2608 tmp = priv->progress_widgets;
2609 if (mode == TOOLBAR_MODE_TRANSFER) {
2611 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2613 tmp = g_slist_next (tmp);
2616 /* If no more operations are being observed, NORMAL mode is enabled again */
2617 if (observers_empty (self)) {
2618 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2624 on_queue_changed (ModestMailOperationQueue *queue,
2625 ModestMailOperation *mail_op,
2626 ModestMailOperationQueueNotification type,
2627 ModestMainWindow *self)
2629 ModestMainWindowPrivate *priv;
2631 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2633 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2634 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2636 "operation-started",
2637 G_CALLBACK (on_mail_operation_started),
2639 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2641 "operation-finished",
2642 G_CALLBACK (on_mail_operation_finished),
2644 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2645 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2647 "operation-started");
2648 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2650 "operation-finished");
2655 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2657 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2659 ModestAccountMgr *mgr;
2660 ModestAccountSettings *settings;
2661 ModestServerAccountSettings *store_settings = NULL;
2663 /* Get account data */
2664 mgr = modest_runtime_get_account_mgr ();
2665 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2667 store_settings = modest_account_settings_get_store_settings (settings);
2669 /* Set the new visible & active account */
2670 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2671 const gchar *account_name;
2673 account_name = modest_account_settings_get_account_name (settings);
2675 modest_folder_view_set_account_id_of_visible_server_account
2677 modest_server_account_settings_get_account_name (store_settings));
2678 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2679 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2681 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2682 if (action != NULL) {
2683 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2684 modest_utils_toggle_action_set_active_block_notify (
2685 GTK_TOGGLE_ACTION (action),
2693 g_object_unref (store_settings);
2694 g_object_unref (settings);
2698 /* Make sure that at least one account is "viewed": */
2700 set_at_least_one_account_visible(ModestMainWindow *self)
2702 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2703 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2705 if (!(priv->folder_view)) {
2706 /* It is too early to do this. */
2710 const gchar *active_server_account_name =
2711 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2713 if (!active_server_account_name ||
2714 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2716 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2717 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2718 if (default_modest_name) {
2719 set_account_visible (self, default_modest_name);
2720 } else if (first_modest_name) {
2721 set_account_visible (self, first_modest_name);
2723 g_free (first_modest_name);
2724 g_free (default_modest_name);
2729 on_show_account_action_toggled (GtkToggleAction *action,
2732 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2734 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2735 if (gtk_toggle_action_get_active (action))
2736 set_account_visible (self, acc_name);
2740 refresh_account (const gchar *account_name)
2744 /* win must already exists here, obviously */
2745 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2748 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2752 /* If account_name == NULL, we must update all (option All) */
2754 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2756 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2761 on_refresh_account_action_activated (GtkAction *action,
2764 refresh_account ((const gchar*) user_data);
2768 on_send_receive_csm_activated (GtkMenuItem *item,
2771 refresh_account ((const gchar*) user_data);
2775 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2777 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2779 hildon_banner_show_information (NULL, NULL,
2780 _CS("ckct_ib_cannot_zoom_here"));
2786 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2788 ModestMainWindow *main_window = NULL;
2790 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2791 main_window = MODEST_MAIN_WINDOW (userdata);
2793 /* Update toolbar dimming state */
2794 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2795 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2801 on_header_view_focus_in (GtkWidget *widget,
2802 GdkEventFocus *event,
2805 ModestMainWindow *main_window = NULL;
2807 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2809 main_window = MODEST_MAIN_WINDOW (userdata);
2811 /* Update toolbar dimming state */
2812 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2813 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2819 on_folder_selection_changed (ModestFolderView *folder_view,
2820 TnyFolderStore *folder_store,
2822 ModestMainWindow *main_window)
2824 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2825 GtkAction *action = NULL;
2826 gboolean show_reply = TRUE;
2827 gboolean show_forward = TRUE;
2828 gboolean show_cancel_send = FALSE;
2829 gboolean show_clipboard = TRUE;
2830 gboolean show_delete = TRUE;
2833 if (TNY_IS_ACCOUNT (folder_store)) {
2834 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2835 } else if (TNY_IS_FOLDER (folder_store)) {
2836 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2837 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2838 TNY_FOLDER (folder_store));
2839 switch (folder_type) {
2840 case TNY_FOLDER_TYPE_DRAFTS:
2841 show_clipboard = show_delete = TRUE;
2842 show_reply = show_forward = show_cancel_send = FALSE;
2844 case TNY_FOLDER_TYPE_SENT:
2845 show_forward = show_clipboard = show_delete = TRUE;
2846 show_reply = show_cancel_send = FALSE;
2848 case TNY_FOLDER_TYPE_OUTBOX:
2849 show_clipboard = show_delete = show_cancel_send = TRUE;
2850 show_reply = show_forward = FALSE;
2852 case TNY_FOLDER_TYPE_INVALID:
2853 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2856 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2857 show_cancel_send = FALSE;
2860 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2861 show_cancel_send = FALSE;
2866 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2867 gtk_action_set_visible (action, show_reply);
2868 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2869 gtk_action_set_visible (action, show_reply);
2870 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2871 gtk_action_set_visible (action, show_forward);
2872 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2873 gtk_action_set_visible (action, show_cancel_send);
2874 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2875 gtk_action_set_visible (action, show_delete);
2877 /* We finally call to the ui actions handler, after updating properly
2878 * the header view CSM */
2879 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2883 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2884 GtkTreeModel *model,
2885 GtkTreeRowReference *row_reference,
2886 ModestMainWindow *self)
2888 ModestMainWindowPrivate *priv = NULL;
2889 GtkTreeModel *header_model = NULL;
2890 GtkTreePath *path = NULL;
2892 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2893 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2894 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2896 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2897 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2899 /* Do nothing if we changed the folder in the main view */
2900 if (header_model != model)
2903 /* Select the message in the header view */
2904 path = gtk_tree_row_reference_get_path (row_reference);
2905 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2907 gtk_tree_path_free (path);
2913 updating_banner_destroyed (gpointer data,
2914 GObject *where_the_object_was)
2916 ModestMainWindowPrivate *priv = NULL;
2918 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2920 priv->updating_banner = NULL;
2924 show_updating_banner (gpointer user_data)
2926 ModestMainWindowPrivate *priv = NULL;
2928 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2930 if (priv->updating_banner == NULL) {
2932 /* We're outside the main lock */
2933 gdk_threads_enter ();
2934 priv->updating_banner =
2935 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2936 _CS ("ckdg_pb_updating"));
2938 /* We need this because banners in Maemo could be
2939 destroyed by dialogs so we need to properly update
2940 our reference to it */
2941 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2942 updating_banner_destroyed,
2944 gdk_threads_leave ();
2947 /* Remove timeout */
2948 priv->updating_banner_timeout = 0;
2953 * We use this function to show/hide a progress banner showing
2954 * "Updating" while the header view is being filled. We're not showing
2955 * it unless the update takes more than 2 seconds
2957 * If starting = TRUE then the refresh is starting, otherwise it means
2958 * that is has just finished
2961 on_updating_msg_list (ModestHeaderView *header_view,
2965 ModestMainWindowPrivate *priv = NULL;
2967 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2969 /* Remove old timeout */
2970 if (priv->updating_banner_timeout > 0) {
2971 g_source_remove (priv->updating_banner_timeout);
2972 priv->updating_banner_timeout = 0;
2975 /* Create a new timeout */
2977 priv->updating_banner_timeout =
2978 g_timeout_add (2000, show_updating_banner, user_data);
2980 /* Remove the banner if exists */
2981 if (priv->updating_banner) {
2982 gtk_widget_destroy (priv->updating_banner);
2983 priv->updating_banner = NULL;
2989 modest_main_window_screen_is_on (ModestMainWindow *self)
2991 ModestMainWindowPrivate *priv = NULL;
2993 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2995 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2997 return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
3001 remove_banners (ModestMainWindow *window)
3003 ModestMainWindowPrivate *priv;
3005 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
3007 if (priv->opening_banner_timeout > 0) {
3008 g_source_remove (priv->opening_banner_timeout);
3009 priv->opening_banner_timeout = 0;
3012 if (priv->opening_banner != NULL) {
3013 gtk_widget_destroy (priv->opening_banner);
3014 priv->opening_banner = NULL;
3017 if (priv->updating_banner_timeout > 0) {
3018 g_source_remove (priv->updating_banner_timeout);
3019 priv->updating_banner_timeout = 0;
3022 if (priv->updating_banner != NULL) {
3023 gtk_widget_destroy (priv->updating_banner);
3024 priv->updating_banner = NULL;
3030 on_window_hide (GObject *gobject,
3034 g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
3036 if (!GTK_WIDGET_VISIBLE (gobject)) {
3037 TnyFolderStore *folder_store;
3038 ModestMainWindowPrivate *priv;
3040 /* Remove the currently shown banners */
3041 remove_banners (MODEST_MAIN_WINDOW (gobject));
3043 /* Force the folder view to sync the currently selected folder
3044 to save the read/unread status and to expunge messages */
3045 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
3046 folder_store = modest_folder_view_get_selected (priv->folder_view);
3047 if (TNY_IS_FOLDER (folder_store)) {
3048 ModestMailOperation *mail_op;
3050 mail_op = modest_mail_operation_new (NULL);
3051 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3053 modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
3054 g_object_unref (mail_op);
3055 g_object_unref (folder_store);
3061 on_window_destroy (GtkObject *widget,
3064 g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
3066 remove_banners (MODEST_MAIN_WINDOW (widget));
3070 opening_banner_destroyed (gpointer data,
3071 GObject *where_the_object_was)
3073 ModestMainWindowPrivate *priv = NULL;
3075 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
3077 priv->opening_banner = NULL;
3081 show_opening_banner (gpointer user_data)
3083 ModestMainWindowPrivate *priv = NULL;
3085 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
3087 if (priv->opening_banner == NULL) {
3089 /* We're outside the main lock */
3090 gdk_threads_enter ();
3091 priv->opening_banner =
3092 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
3093 _("mail_me_opening"));
3095 /* We need this because banners in Maemo could be
3096 destroyed by dialogs so we need to properly update
3097 our reference to it */
3098 g_object_weak_ref (G_OBJECT (priv->opening_banner),
3099 opening_banner_destroyed,
3102 /* We need this because banners in Maemo could be
3103 destroyed by dialogs so we need to properly update
3104 our reference to it */
3105 g_object_weak_ref (G_OBJECT (priv->updating_banner),
3106 updating_banner_destroyed,
3108 gdk_threads_leave ();
3111 /* Remove timeout */
3112 priv->opening_banner_timeout = 0;