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 "modest-osso-state-saving.h"
65 #include "modest-text-utils.h"
66 #include "modest-signal-mgr.h"
68 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
75 /* 'private'/'protected' functions */
76 static void modest_main_window_class_init (ModestMainWindowClass *klass);
77 static void modest_main_window_init (ModestMainWindow *obj);
78 static void modest_main_window_finalize (GObject *obj);
80 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
81 GdkEventWindowState *event,
84 static void connect_signals (ModestMainWindow *self);
86 static void modest_main_window_disconnect_signals (ModestWindow *self);
88 static void restore_settings (ModestMainWindow *self,
89 gboolean do_folder_view_too);
91 static void save_state (ModestWindow *self);
93 static void update_menus (ModestMainWindow* self);
95 static void modest_main_window_show_toolbar (ModestWindow *window,
96 gboolean show_toolbar);
98 static void cancel_progressbar (GtkToolButton *toolbutton,
99 ModestMainWindow *self);
101 static void on_queue_changed (ModestMailOperationQueue *queue,
102 ModestMailOperation *mail_op,
103 ModestMailOperationQueueNotification type,
104 ModestMainWindow *self);
106 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
108 static void on_account_inserted (TnyAccountStore *accoust_store,
112 static void on_account_removed (TnyAccountStore *accoust_store,
116 static void on_account_changed (TnyAccountStore *account_store,
120 static void on_default_account_changed (ModestAccountMgr* mgr,
123 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
127 static void on_configuration_key_changed (ModestConf* conf,
129 ModestConfEvent event,
130 ModestConfNotificationId id,
131 ModestMainWindow *self);
133 static void set_toolbar_mode (ModestMainWindow *self,
134 ModestToolBarModes mode);
136 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
138 static void on_show_account_action_toggled (GtkToggleAction *action,
141 static void on_refresh_account_action_activated (GtkAction *action,
144 static void on_send_receive_csm_activated (GtkMenuItem *item,
147 static void on_msg_count_changed (ModestHeaderView *header_view,
149 TnyFolderChange *change,
150 ModestMainWindow *main_window);
152 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
155 static GtkWidget * create_empty_view (void);
157 static gboolean on_folder_view_focus_in (GtkWidget *widget,
158 GdkEventFocus *event,
161 static gboolean on_header_view_focus_in (GtkWidget *widget,
162 GdkEventFocus *event,
165 static void on_folder_selection_changed (ModestFolderView *folder_view,
166 TnyFolderStore *folder_store,
168 ModestMainWindow *main_window);
170 static void set_at_least_one_account_visible(ModestMainWindow *self);
172 static void on_updating_msg_list (ModestHeaderView *header_view,
176 static gboolean restore_paned_timeout_handler (gpointer *data);
178 static gboolean show_opening_banner (gpointer user_data);
180 static void on_window_destroy (GtkObject *widget,
183 static void on_window_hide (GObject *gobject,
187 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
188 struct _ModestMainWindowPrivate {
189 GtkWidget *msg_paned;
190 GtkWidget *main_paned;
191 GtkWidget *main_vbox;
192 GtkWidget *contents_widget;
193 GtkWidget *empty_view;
195 /* Progress observers */
196 GtkWidget *progress_bar;
197 GSList *progress_widgets;
200 GtkWidget *progress_toolitem;
201 GtkWidget *cancel_toolitem;
202 GtkWidget *sort_toolitem;
203 GtkWidget *refresh_toolitem;
204 ModestToolBarModes current_toolbar_mode;
206 /* Merge ids used to add/remove accounts to the ViewMenu*/
207 GByteArray *merge_ids;
208 GtkActionGroup *view_additions_group;
210 /* On-demand widgets */
211 GtkWidget *accounts_popup;
212 GtkWidget *details_widget;
214 /* Optimized view enabled */
215 gboolean optimized_view;
217 /* Optimized view enabled */
218 gboolean send_receive_in_progress;
220 ModestHeaderView *header_view;
221 ModestFolderView *folder_view;
223 ModestMainWindowStyle style;
224 ModestMainWindowContentsStyle contents_style;
225 gboolean wait_for_settings;
227 guint progress_bar_timeout;
228 guint restore_paned_timeout;
230 /* Signal handler UIDs */
231 GList *queue_err_signals;
234 /* "Updating" banner for header view */
235 GtkWidget *updating_banner;
236 guint updating_banner_timeout;
238 /* "Opening" banner for header view */
239 GtkWidget *opening_banner;
240 guint opening_banner_timeout;
243 osso_display_state_t display_state;
245 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
246 MODEST_TYPE_MAIN_WINDOW, \
247 ModestMainWindowPrivate))
249 typedef struct _GetMsgAsyncHelper {
250 ModestMainWindowPrivate *main_window_private;
252 ModestTnyMsgReplyType reply_type;
253 ModestTnyMsgForwardType forward_type;
260 static GtkWindowClass *parent_class = NULL;
263 /* Private actions */
264 /* This is the context sensitive menu: */
265 static const GtkActionEntry modest_folder_view_action_entries [] = {
267 /* Folder View CSM actions */
268 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
269 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
270 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
271 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
272 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
273 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_csm_help) },
276 static const GtkActionEntry modest_header_view_action_entries [] = {
278 /* Header View CSM actions */
279 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
280 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
281 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
282 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
283 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
284 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
285 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
286 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
287 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
288 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
291 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
292 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
295 /************************************************************************/
298 modest_main_window_get_type (void)
300 static GType my_type = 0;
302 static const GTypeInfo my_info = {
303 sizeof(ModestMainWindowClass),
304 NULL, /* base init */
305 NULL, /* base finalize */
306 (GClassInitFunc) modest_main_window_class_init,
307 NULL, /* class finalize */
308 NULL, /* class data */
309 sizeof(ModestMainWindow),
311 (GInstanceInitFunc) modest_main_window_init,
314 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
322 modest_main_window_class_init (ModestMainWindowClass *klass)
324 GObjectClass *gobject_class;
325 gobject_class = (GObjectClass*) klass;
326 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
328 parent_class = g_type_class_peek_parent (klass);
329 gobject_class->finalize = modest_main_window_finalize;
331 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
333 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
334 modest_window_class->save_state_func = save_state;
335 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
336 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
337 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
341 modest_main_window_init (ModestMainWindow *obj)
343 ModestMainWindowPrivate *priv;
345 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
347 priv->queue_err_signals = NULL;
348 priv->msg_paned = NULL;
349 priv->main_paned = NULL;
350 priv->main_vbox = NULL;
351 priv->header_view = NULL;
352 priv->folder_view = NULL;
353 priv->contents_widget = NULL;
354 priv->accounts_popup = NULL;
355 priv->details_widget = NULL;
356 priv->empty_view = NULL;
357 priv->progress_widgets = NULL;
358 priv->progress_bar = NULL;
359 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
360 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
361 priv->wait_for_settings = TRUE;
362 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
363 priv->merge_ids = NULL;
364 priv->optimized_view = FALSE;
365 priv->send_receive_in_progress = FALSE;
366 priv->progress_bar_timeout = 0;
367 priv->restore_paned_timeout = 0;
368 priv->sighandlers = NULL;
369 priv->updating_banner = NULL;
370 priv->updating_banner_timeout = 0;
371 priv->opening_banner = NULL;
372 priv->opening_banner_timeout = 0;
373 priv->display_state = OSSO_DISPLAY_ON;
375 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
377 "applications_email_mainview");
381 modest_main_window_finalize (GObject *obj)
383 ModestMainWindowPrivate *priv;
385 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
387 /* Sanity check: shouldn't be needed, the window mgr should
388 call this function before */
389 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
390 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
392 if (priv->empty_view) {
393 g_object_unref (priv->empty_view);
394 priv->empty_view = NULL;
397 if (priv->header_view) {
398 g_object_unref (priv->header_view);
399 priv->header_view = NULL;
402 g_slist_free (priv->progress_widgets);
404 g_byte_array_free (priv->merge_ids, TRUE);
406 if (priv->progress_bar_timeout > 0) {
407 g_source_remove (priv->progress_bar_timeout);
408 priv->progress_bar_timeout = 0;
411 if (priv->updating_banner_timeout > 0) {
412 g_source_remove (priv->updating_banner_timeout);
413 priv->updating_banner_timeout = 0;
416 if (priv->updating_banner) {
417 gtk_widget_destroy (priv->updating_banner);
418 priv->updating_banner = NULL;
421 if (priv->opening_banner_timeout > 0) {
422 g_source_remove (priv->opening_banner_timeout);
423 priv->opening_banner_timeout = 0;
426 if (priv->opening_banner) {
427 gtk_widget_destroy (priv->opening_banner);
428 priv->opening_banner = NULL;
431 if (priv->restore_paned_timeout > 0) {
432 g_source_remove (priv->restore_paned_timeout);
433 priv->restore_paned_timeout = 0;
436 G_OBJECT_CLASS(parent_class)->finalize (obj);
440 modest_main_window_get_child_widget (ModestMainWindow *self,
441 ModestMainWindowWidgetType widget_type)
443 ModestMainWindowPrivate *priv;
446 g_return_val_if_fail (self && MODEST_IS_MAIN_WINDOW(self), NULL);
447 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
450 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
452 switch (widget_type) {
453 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
454 widget = (GtkWidget*)priv->header_view; break;
455 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
456 widget = (GtkWidget*)priv->folder_view; break;
461 /* Note that the window could have been destroyed, and so
462 their children, but still have some references */
463 return (widget && GTK_IS_WIDGET(widget)) ? GTK_WIDGET(widget) : NULL;
467 restore_paned_timeout_handler (gpointer *data)
469 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
470 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
473 /* Timeouts are outside the main lock */
474 gdk_threads_enter ();
475 if (GTK_WIDGET_VISIBLE (main_window)) {
476 conf = modest_runtime_get_conf ();
477 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
478 MODEST_CONF_MAIN_PANED_KEY);
480 gdk_threads_leave ();
487 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
490 ModestMainWindowPrivate *priv;
492 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
494 conf = modest_runtime_get_conf ();
496 modest_widget_memory_restore (conf, G_OBJECT(self),
497 MODEST_CONF_MAIN_WINDOW_KEY);
499 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
500 MODEST_CONF_HEADER_VIEW_KEY);
502 if (do_folder_view_too)
503 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
504 MODEST_CONF_FOLDER_VIEW_KEY);
506 /* modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned), */
507 /* MODEST_CONF_MAIN_PANED_KEY); */
509 g_timeout_add (250, (GSourceFunc) restore_paned_timeout_handler, self);
511 /* We need to force a redraw here in order to get the right
512 position of the horizontal paned separator */
513 gtk_widget_show (GTK_WIDGET (self));
518 save_state (ModestWindow *window)
521 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
522 ModestMainWindowPrivate *priv;
524 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
525 conf = modest_runtime_get_conf ();
527 modest_widget_memory_save (conf,G_OBJECT(self),
528 MODEST_CONF_MAIN_WINDOW_KEY);
529 /* Only save main paned position if we're in split mode */
530 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
531 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
532 MODEST_CONF_MAIN_PANED_KEY);
533 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
534 MODEST_CONF_FOLDER_VIEW_KEY);
538 compare_display_names (ModestAccountSettings *a,
539 ModestAccountSettings *b)
541 return g_utf8_collate (modest_account_settings_get_display_name (a),
542 modest_account_settings_get_display_name (b));
546 /* We use this function to prevent the send&receive CSM to be shown
547 when there are less than two account */
549 tap_and_hold_query_cb (GtkWidget *widget, GdkEvent *event)
555 update_menus (ModestMainWindow* self)
557 GSList *account_names, *iter, *accounts;
558 ModestMainWindowPrivate *priv;
559 ModestWindowPrivate *parent_priv;
560 ModestAccountMgr *mgr;
561 gint i, num_accounts;
563 gchar *default_account;
564 const gchar *active_account_name;
565 GtkWidget *send_receive_button, *item;
566 GtkAction *send_receive_all = NULL;
569 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
570 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
572 /* Get enabled account IDs */
573 mgr = modest_runtime_get_account_mgr ();
574 account_names = modest_account_mgr_account_names (mgr, TRUE);
575 iter = account_names;
579 ModestAccountSettings *settings =
580 modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
581 accounts = g_slist_prepend (accounts, settings);
585 modest_account_mgr_free_account_names (account_names);
586 account_names = NULL;
588 /* Order the list of accounts by its display name */
589 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
590 num_accounts = g_slist_length (accounts);
592 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
593 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
594 gtk_action_set_visible (send_receive_all, num_accounts > 0);
596 /* Delete old send&receive popup items. We can not just do a
597 menu_detach because it does not work well with
599 if (priv->accounts_popup)
600 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
601 (GtkCallback) gtk_widget_destroy, NULL);
603 /* Delete old entries in the View menu. Do not free groups, it
605 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
607 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
608 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
609 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
610 GTK_ACTION_GROUP (groups->data));
613 if (priv->merge_ids) {
614 for (i = 0; i < priv->merge_ids->len; i++)
615 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
616 g_byte_array_free (priv->merge_ids, TRUE);
618 /* We need to call this in order to ensure
619 that the new actions are added in the right
620 order (alphabetical) */
621 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
623 groups = g_list_next (groups);
625 priv->merge_ids = g_byte_array_sized_new (num_accounts);
627 /* Get send receive button */
628 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
629 "/ToolBar/ToolbarSendReceive");
631 /* Create the menu */
632 if (num_accounts > 1) {
633 if (!priv->accounts_popup)
634 priv->accounts_popup = gtk_menu_new ();
635 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
636 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
637 g_signal_connect (G_OBJECT (item),
639 G_CALLBACK (on_send_receive_csm_activated),
641 item = gtk_separator_menu_item_new ();
642 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
645 /* Create a new action group */
646 default_account = modest_account_mgr_get_default_account (mgr);
647 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
649 if (!active_account_name)
650 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
652 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
654 for (i = 0; i < num_accounts; i++) {
655 gchar *display_name = NULL;
656 const gchar *account_name;
657 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
660 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
663 account_name = modest_account_settings_get_account_name (settings);
665 if (default_account && account_name &&
666 !(strcmp (default_account, account_name) == 0)) {
667 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
668 modest_account_settings_get_display_name (settings));
670 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
671 modest_account_settings_get_display_name (settings));
676 /* Create action and add it to the action group. The
677 action name must be the account name, this way we
678 could know in the handlers the account to show */
679 if (settings && account_name) {
680 gchar* item_name, *refresh_action_name;
682 GtkAction *view_account_action, *refresh_account_action;
683 gchar *escaped_display_name;
685 escaped_display_name = modest_text_utils_escape_mnemonics (display_name);
687 view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
688 escaped_display_name, NULL, NULL, 0));
689 g_free (escaped_display_name);
690 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
691 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
692 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
694 if (active_account_name) {
695 if (active_account_name && account_name &&
696 (strcmp (active_account_name, account_name) == 0)) {
697 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
701 /* Add ui from account data. We allow 2^9-1 account
702 changes in a single execution because we're
703 downcasting the guint to a guint8 in order to use a
704 GByteArray. It should be enough :-) */
705 item_name = g_strconcat (account_name, "Menu", NULL);
706 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
707 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
708 gtk_ui_manager_add_ui (parent_priv->ui_manager,
710 "/MenuBar/ViewMenu/ViewMenuAdditions",
713 GTK_UI_MANAGER_MENUITEM,
716 /* Connect the action signal "activate" */
717 g_signal_connect_after (G_OBJECT (view_account_action),
719 G_CALLBACK (on_show_account_action_toggled),
722 /* Create the items for the Tools->Send&Receive submenu */
723 refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
724 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
725 display_name, NULL, NULL);
726 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
728 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
729 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
730 gtk_ui_manager_add_ui (parent_priv->ui_manager,
732 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
735 GTK_UI_MANAGER_MENUITEM,
737 g_free (refresh_action_name);
739 g_signal_connect_data (G_OBJECT (refresh_account_action),
741 G_CALLBACK (on_refresh_account_action_activated),
742 g_strdup (account_name),
743 (GClosureNotify) g_free,
746 /* Create item and add it to the send&receive
747 CSM. If there is only one account then
749 if (num_accounts > 1) {
750 GtkWidget *label = gtk_label_new(NULL);
751 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
752 if (default_account && (strcmp(account_name, default_account) == 0)) {
753 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
754 gtk_label_set_markup (GTK_LABEL (label), escaped);
757 gtk_label_set_text (GTK_LABEL (label), display_name);
760 item = gtk_menu_item_new ();
761 gtk_container_add (GTK_CONTAINER (item), label);
763 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup),
765 g_signal_connect_data (G_OBJECT (item),
767 G_CALLBACK (on_send_receive_csm_activated),
768 g_strdup (account_name),
769 (GClosureNotify) g_free,
776 g_free (display_name);
779 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
781 /* We cannot do this in the loop above because this relies on the action
782 * group being inserted. This makes the default account appear in bold.
783 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
784 for (i = 0; i < num_accounts; i++) {
785 gchar *item_name, *path;
787 ModestAccountSettings *settings;
788 const gchar *account_name;
791 settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
792 account_name = modest_account_settings_get_account_name (settings);
793 is_default = (account_name && default_account && !strcmp (account_name, default_account));
795 /* Get the item of the view menu */
796 item_name = g_strconcat (account_name, "Menu", NULL);
797 path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
798 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
802 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
803 if (GTK_IS_LABEL (child)) {
804 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
806 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
807 gtk_label_set_markup (GTK_LABEL (child), bold_name);
810 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
814 /* Get the item of the tools menu */
815 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
816 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
820 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
821 if (GTK_IS_LABEL (child)) {
822 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
824 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
825 gtk_label_set_markup (GTK_LABEL (child), bold_name);
828 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
833 g_object_unref (settings);
836 if (num_accounts > 1) {
837 /* Disconnect the tap-and-hold-query if it's connected */
838 if (modest_signal_mgr_is_connected (priv->sighandlers,
839 G_OBJECT (send_receive_button),
840 "tap-and-hold-query"))
841 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
842 G_OBJECT (send_receive_button),
843 "tap-and-hold-query");
845 /* Mandatory in order to view the menu contents */
846 gtk_widget_show_all (priv->accounts_popup);
848 /* Setup tap_and_hold just if was not done before*/
849 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
850 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
852 /* Connect the tap-and-hold-query in order not to show the CSM */
853 if (!modest_signal_mgr_is_connected (priv->sighandlers,
854 G_OBJECT (send_receive_button),
855 "tap-and-hold-query"))
856 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
857 G_OBJECT (send_receive_button),
858 "tap-and-hold-query",
859 G_CALLBACK (tap_and_hold_query_cb),
864 g_slist_free (accounts);
865 g_free (default_account);
868 /* Make sure that at least one account is viewed if there are any
869 * accounts, for instance when adding the first account: */
870 set_at_least_one_account_visible (self);
874 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
876 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
877 gtk_scrolled_window_add_with_viewport
878 (GTK_SCROLLED_WINDOW(win), widget);
880 gtk_container_add (GTK_CONTAINER(win),
891 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
893 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
895 GList *oerrsignals = priv->queue_err_signals;
896 while (oerrsignals) {
897 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
898 g_signal_handler_disconnect (esignal->queue, esignal->signal);
899 g_slice_free (QueueErrorSignal, esignal);
900 oerrsignals = g_list_next (oerrsignals);
902 g_list_free (priv->queue_err_signals);
903 priv->queue_err_signals = NULL;
908 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
910 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
913 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
917 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
919 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
921 /* Update visibility */
924 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
928 modest_main_window_disconnect_signals (ModestWindow *self)
930 ModestMainWindowPrivate *priv;
931 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
933 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
934 priv->sighandlers = NULL;
938 connect_signals (ModestMainWindow *self)
940 ModestWindowPrivate *parent_priv;
941 ModestMainWindowPrivate *priv;
944 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
945 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
950 modest_signal_mgr_connect (priv->sighandlers,
951 G_OBJECT(priv->folder_view), "key-press-event",
952 G_CALLBACK(on_inner_widgets_key_pressed), self);
954 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
955 "folder_selection_changed",
956 G_CALLBACK (on_folder_selection_changed),
959 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
960 "folder-display-name-changed",
961 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
964 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
966 G_CALLBACK (on_folder_view_focus_in),
969 /* Folder view CSM */
970 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
971 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
972 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
973 G_CALLBACK(_folder_view_csm_menu_activated),
977 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
978 G_CALLBACK(modest_ui_actions_on_header_selected), self);
980 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
981 G_CALLBACK(modest_ui_actions_on_header_activated), self);
983 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
984 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
986 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
987 G_CALLBACK(on_inner_widgets_key_pressed), self);
989 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
990 G_CALLBACK(on_msg_count_changed), self);
992 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
993 G_CALLBACK (on_header_view_focus_in), self);
995 modest_signal_mgr_connect (priv->sighandlers,
996 G_OBJECT (priv->header_view),
998 G_CALLBACK (on_updating_msg_list),
1001 /* Header view CSM */
1002 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
1003 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
1005 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
1006 G_CALLBACK(_header_view_csm_menu_activated),
1011 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
1012 G_CALLBACK (modest_main_window_window_state_event),
1014 /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
1015 * in destroy stage */
1016 g_signal_connect (G_OBJECT (self), "destroy", G_CALLBACK (on_window_destroy), NULL);
1018 g_signal_connect (G_OBJECT (self), "notify::visible", G_CALLBACK (on_window_hide), NULL);
1020 /* Mail Operation Queue */
1022 modest_signal_mgr_connect (priv->sighandlers,
1023 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
1025 G_CALLBACK (on_queue_changed), self);
1027 /* Track changes in the device name */
1029 modest_signal_mgr_connect (priv->sighandlers,
1030 G_OBJECT(modest_runtime_get_conf ()),
1032 G_CALLBACK (on_configuration_key_changed),
1035 /* Track account changes. We need to refresh the toolbar */
1037 modest_signal_mgr_connect (priv->sighandlers,
1038 G_OBJECT (modest_runtime_get_account_store ()),
1040 G_CALLBACK (on_account_inserted),
1043 modest_signal_mgr_connect (priv->sighandlers,
1044 G_OBJECT (modest_runtime_get_account_store ()),
1046 G_CALLBACK (on_account_removed),
1049 /* We need to refresh the send & receive menu to change the bold
1050 * account when the default account changes. */
1052 modest_signal_mgr_connect (priv->sighandlers,
1053 G_OBJECT (modest_runtime_get_account_mgr ()),
1054 "default_account_changed",
1055 G_CALLBACK (on_default_account_changed),
1060 modest_signal_mgr_connect (priv->sighandlers,
1061 G_OBJECT (modest_runtime_get_account_store ()),
1063 G_CALLBACK (on_account_changed),
1068 on_hildon_program_is_topmost_notify(GObject *self,
1069 GParamSpec *propert_param,
1072 HildonProgram *app = HILDON_PROGRAM (self);
1074 /* Note that use of hildon_program_set_can_hibernate()
1075 * is generally referred to as "setting the killable flag",
1076 * though hibernation does not seem equal to death.
1079 if (hildon_program_get_is_topmost (app)) {
1080 /* Prevent hibernation when the progam comes to the foreground,
1081 * because hibernation should only happen when the application
1082 * is in the background: */
1083 hildon_program_set_can_hibernate (app, FALSE);
1085 /* Remove new mail visual notifications */
1086 modest_platform_remove_new_mail_notifications (TRUE);
1088 /* Allow hibernation if the program has gone to the background: */
1090 /* However, prevent hibernation while the settings are being changed: */
1091 const gboolean hibernation_prevented =
1092 modest_window_mgr_get_hibernation_is_prevented (
1093 modest_runtime_get_window_mgr ());
1095 if (hibernation_prevented)
1096 hildon_program_set_can_hibernate (app, FALSE);
1098 /* Allow hibernation, after saving the state: */
1099 modest_osso_save_state();
1100 hildon_program_set_can_hibernate (app, TRUE);
1107 GtkWidget *folder_win;
1112 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1114 ShowHelper *helper = (ShowHelper *) user_data;
1115 GtkWidget *folder_win = helper->folder_win;
1116 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1118 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1119 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1121 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1123 /* Connect signals */
1124 connect_signals (MODEST_MAIN_WINDOW (self));
1126 /* Set account store */
1127 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1128 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1130 /* Load previous osso state, for instance if we are being restored from
1132 modest_osso_load_state ();
1134 /* Restore window & widget settings */
1135 priv->wait_for_settings = TRUE;
1136 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1137 priv->wait_for_settings = FALSE;
1139 /* Check if accounts exist and show the account wizard if not */
1140 gboolean accounts_exist =
1141 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1143 if (!accounts_exist) {
1144 /* This is necessary to have the main window shown behind the dialog
1145 It's an ugly hack... jschmid */
1146 gtk_widget_show_all(GTK_WIDGET(self));
1147 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1149 update_menus (MODEST_MAIN_WINDOW (self));
1152 /* Never call this function again (NOTE that it could happen
1153 as we hide the main window instead of closing it while
1154 there are operations ongoing) and free the helper */
1155 g_signal_handler_disconnect (self, helper->handler_id);
1156 g_slice_free (ShowHelper, helper);
1160 osso_display_event_cb (osso_display_state_t state,
1163 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1165 priv->display_state = state;
1167 /* Stop blinking if the screen becomes on */
1168 if (priv->display_state == OSSO_DISPLAY_ON)
1169 modest_platform_remove_new_mail_notifications (TRUE);
1173 modest_main_window_new (void)
1175 ModestMainWindow *self = NULL;
1176 ModestMainWindowPrivate *priv = NULL;
1177 ModestWindowPrivate *parent_priv = NULL;
1178 GtkWidget *folder_win = NULL;
1179 ModestDimmingRulesGroup *menu_rules_group = NULL;
1180 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1181 GtkActionGroup *action_group = NULL;
1182 GError *error = NULL;
1184 ModestConf *conf = NULL;
1185 GtkAction *action = NULL;
1186 GdkPixbuf *window_icon;
1189 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1190 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1191 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1193 parent_priv->ui_manager = gtk_ui_manager_new();
1194 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1196 action_group = gtk_action_group_new ("ModestMainWindowActions");
1197 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1199 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1200 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1202 /* Add common actions */
1203 gtk_action_group_add_actions (action_group,
1204 modest_action_entries,
1205 G_N_ELEMENTS (modest_action_entries),
1208 gtk_action_group_add_actions (action_group,
1209 modest_folder_view_action_entries,
1210 G_N_ELEMENTS (modest_folder_view_action_entries),
1213 gtk_action_group_add_actions (action_group,
1214 modest_header_view_action_entries,
1215 G_N_ELEMENTS (modest_header_view_action_entries),
1218 gtk_action_group_add_toggle_actions (action_group,
1219 modest_toggle_action_entries,
1220 G_N_ELEMENTS (modest_toggle_action_entries),
1223 gtk_action_group_add_toggle_actions (action_group,
1224 modest_main_window_toggle_action_entries,
1225 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1228 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1229 g_object_unref (action_group);
1231 /* Load the UI definition */
1232 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1233 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1234 if (error != NULL) {
1235 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1236 g_error_free (error);
1240 /* Add common dimming rules */
1241 modest_dimming_rules_group_add_rules (menu_rules_group,
1242 modest_main_window_menu_dimming_entries,
1243 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1244 MODEST_WINDOW (self));
1245 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1246 modest_main_window_toolbar_dimming_entries,
1247 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1248 MODEST_WINDOW (self));
1250 /* Insert dimming rules group for this window */
1251 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1252 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1253 g_object_unref (menu_rules_group);
1254 g_object_unref (toolbar_rules_group);
1256 /* Add accelerators */
1257 gtk_window_add_accel_group (GTK_WINDOW (self),
1258 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1260 /* Menubar. Update the state of some toggles */
1261 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1262 conf = modest_runtime_get_conf ();
1263 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1264 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1265 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1266 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1267 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1268 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1269 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1270 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1271 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1272 gtk_widget_show (parent_priv->menubar);
1274 /* Get device name */
1275 modest_maemo_utils_get_device_name ();
1279 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1280 g_object_ref (priv->header_view);
1281 if (!priv->header_view)
1282 g_printerr ("modest: cannot instantiate header view\n");
1283 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1284 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1285 MODEST_CONF_HEADER_VIEW_KEY);
1287 /* Other style properties of header view */
1288 g_object_set (G_OBJECT (priv->header_view),
1289 "rules-hint", FALSE,
1291 /* gtk_widget_show (priv->header_view); */
1294 priv->empty_view = create_empty_view ();
1295 gtk_widget_show (priv->empty_view);
1296 g_object_ref (priv->empty_view);
1298 /* Create scrolled windows */
1299 folder_win = gtk_scrolled_window_new (NULL, NULL);
1300 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1301 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1303 GTK_POLICY_AUTOMATIC);
1304 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1306 GTK_POLICY_AUTOMATIC);
1307 /* gtk_widget_show (priv->contents_widget); */
1310 priv->main_paned = gtk_hpaned_new ();
1311 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1312 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1313 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1315 /* putting it all together... */
1316 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1317 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1318 gtk_widget_show (priv->main_vbox);
1320 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1322 app = hildon_program_get_instance ();
1323 hildon_program_add_window (app, HILDON_WINDOW (self));
1325 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1326 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1328 /* Connect to "show" action. We delay the creation of some
1329 elements until that moment */
1330 helper = g_slice_new0 (ShowHelper);
1331 helper->folder_win = folder_win;
1332 helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1333 G_CALLBACK (modest_main_window_on_show),
1336 /* Set window icon */
1337 window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1339 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1340 g_object_unref (window_icon);
1343 /* Listen for changes in the screen, we don't want to show a
1344 led pattern when the display is on for example */
1345 osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1346 osso_display_event_cb,
1349 /* Dont't restore settings here,
1350 * because it requires a gtk_widget_show(),
1351 * and we don't want to do that until later,
1352 * so that the UI is not visible for non-menu D-Bus activation.
1355 return MODEST_WINDOW(self);
1359 modest_main_window_set_style (ModestMainWindow *self,
1360 ModestMainWindowStyle style)
1362 ModestMainWindowPrivate *priv;
1363 ModestWindowPrivate *parent_priv;
1366 GtkTreeSelection *sel;
1369 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1371 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1372 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1374 /* no change -> nothing to do */
1375 if (priv->style == style)
1378 /* Get toggle button and update the state if needed. This will
1379 happen only when the set_style is not invoked from the UI,
1380 for example when it's called from widget memory */
1381 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1382 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1383 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1384 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1385 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1386 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1387 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1390 /* We need to store the selection because it's lost when the
1391 widget is reparented */
1392 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1393 rows = gtk_tree_selection_get_selected_rows (sel, NULL);
1395 priv->style = style;
1397 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1399 if (!priv->wait_for_settings)
1400 modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT (priv->main_paned),
1401 MODEST_CONF_MAIN_PANED_KEY);
1402 /* Remove main paned */
1403 g_object_ref (priv->main_paned);
1404 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1406 /* Reparent the contents widget to the main vbox */
1407 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1410 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1411 /* Remove header view */
1412 g_object_ref (priv->contents_widget);
1413 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1415 /* Reparent the main paned */
1416 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1417 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1419 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
1423 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1425 g_return_if_reached ();
1428 /* Reselect the previously selected folders. We disable the
1429 dimming rules execution during that time because there is
1430 no need to work out it again and it could take a lot of
1431 time if all the headers are selected */
1433 modest_window_disable_dimming (MODEST_WINDOW (self));
1435 gtk_tree_selection_select_path (sel, (GtkTreePath *) list->data);
1436 list = g_list_next (list);
1438 modest_window_enable_dimming (MODEST_WINDOW (self));
1441 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1444 /* Let header view grab the focus if it's being shown */
1445 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1446 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1448 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
1449 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1451 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1454 /* Check dimming rules */
1455 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1456 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1459 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1462 ModestMainWindowStyle
1463 modest_main_window_get_style (ModestMainWindow *self)
1465 ModestMainWindowPrivate *priv;
1467 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1469 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1474 toolbar_resize (ModestMainWindow *self)
1476 ModestMainWindowPrivate *priv = NULL;
1477 ModestWindowPrivate *parent_priv = NULL;
1479 gint static_button_size;
1480 ModestWindowMgr *mgr;
1482 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1483 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1484 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1486 mgr = modest_runtime_get_window_mgr ();
1487 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1489 if (parent_priv->toolbar) {
1490 /* left size buttons */
1491 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
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/ToolbarMessageReply");
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/ToolbarDeleteMessage");
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);
1503 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1504 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1505 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1506 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1508 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1509 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1510 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1511 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1512 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1513 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1514 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1515 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1523 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1525 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1526 ModestWindowPrivate *parent_priv;
1527 ModestWindowMgr *mgr;
1528 gboolean is_fullscreen;
1529 GtkAction *fs_toggle_action;
1532 mgr = modest_runtime_get_window_mgr ();
1534 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1536 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1538 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1539 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1540 if (is_fullscreen != active) {
1541 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1544 toolbar_resize (MODEST_MAIN_WINDOW (widget));
1552 modest_main_window_show_toolbar (ModestWindow *self,
1553 gboolean show_toolbar)
1555 ModestMainWindowPrivate *priv = NULL;
1556 ModestWindowPrivate *parent_priv = NULL;
1557 GtkWidget *reply_button = NULL, *menu = NULL;
1558 GtkWidget *placeholder = NULL;
1560 const gchar *action_name;
1563 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1564 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1565 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1567 /* Set optimized view status */
1568 priv->optimized_view = !show_toolbar;
1570 if (!parent_priv->toolbar) {
1571 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1573 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1575 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1576 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1577 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1578 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1579 toolbar_resize (MODEST_MAIN_WINDOW (self));
1581 /* Add ProgressBar (Transfer toolbar) */
1582 priv->progress_bar = modest_progress_bar_new ();
1583 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1584 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1585 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1586 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1587 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1589 /* Connect cancel 'clicked' signal to abort progress mode */
1590 g_signal_connect(priv->cancel_toolitem, "clicked",
1591 G_CALLBACK(cancel_progressbar),
1594 /* Add it to the observers list */
1595 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1598 hildon_window_add_toolbar (HILDON_WINDOW (self),
1599 GTK_TOOLBAR (parent_priv->toolbar));
1601 /* Set reply button tap and hold menu */
1602 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1603 "/ToolBar/ToolbarMessageReply");
1604 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1605 "/ToolbarReplyCSM");
1606 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1608 /* Set send & receive button tap and hold menu */
1609 update_menus (MODEST_MAIN_WINDOW (self));
1613 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1614 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1615 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1617 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1618 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1619 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1621 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1623 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1627 /* Update also the actions (to update the toggles in the
1628 menus), we have to do it manually because some other window
1629 of the same time could have changed it (remember that the
1630 toolbar fullscreen mode is shared by all the windows of the
1632 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1633 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1635 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1637 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1638 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1643 on_account_inserted (TnyAccountStore *accoust_store,
1644 TnyAccount *account,
1647 /* Transport accounts and local ones (MMC and the Local
1648 folders account do now cause menu changes */
1649 if (TNY_IS_STORE_ACCOUNT (account) &&
1650 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1652 update_menus (MODEST_MAIN_WINDOW (user_data));
1657 on_default_account_changed (ModestAccountMgr* mgr,
1660 update_menus (MODEST_MAIN_WINDOW (user_data));
1664 on_account_removed (TnyAccountStore *accoust_store,
1665 TnyAccount *account,
1668 /* Transport accounts and local ones (MMC and the Local
1669 folders account do now cause menu changes */
1670 if (TNY_IS_STORE_ACCOUNT (account) &&
1671 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1672 update_menus (MODEST_MAIN_WINDOW (user_data));
1676 on_account_changed (TnyAccountStore *account_store,
1677 TnyAccount *account,
1680 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1682 /* Transport accounts and local ones (MMC and the Local
1683 folders account do now cause menu changes */
1684 if (TNY_IS_STORE_ACCOUNT (account)) {
1685 /* We need to refresh the details widget because it could have changed */
1686 if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1687 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1689 /* Update the menus as well, name could change */
1690 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1691 update_menus (MODEST_MAIN_WINDOW (user_data));
1696 * This function manages the key events used to navigate between
1697 * header and folder views (when the window is in split view)
1700 * -------------------------------------------------
1701 * HeaderView GDK_Left Move focus to folder view
1702 * FolderView GDK_Right Move focus to header view
1704 * There is no need to scroll to selected row, the widgets will be the
1705 * responsibles of doing that (probably managing the focus-in event
1708 on_inner_widgets_key_pressed (GtkWidget *widget,
1712 ModestMainWindowPrivate *priv;
1714 if (event->type == GDK_KEY_RELEASE)
1717 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1719 /* Do nothing if we're in SIMPLE style */
1720 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1723 if (MODEST_IS_HEADER_VIEW (widget)) {
1724 if (event->keyval == GDK_Left)
1725 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1726 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1727 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1728 if (selected_headers > 1) {
1729 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1732 GtkTreePath * cursor_path;
1733 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1734 if (cursor_path == NULL) {
1735 GtkTreeSelection *selection;
1737 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1738 list = gtk_tree_selection_get_selected_rows (selection, NULL);
1741 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1742 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1747 } else if (MODEST_IS_FOLDER_VIEW (widget) && (event->keyval == GDK_Right || event->keyval == GDK_Left)) {
1748 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1749 GtkTreePath *selected_path = NULL;
1750 GtkTreePath *start_path = NULL;
1751 GtkTreePath *end_path = NULL;
1753 GtkTreeSelection *selection;
1755 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1756 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1757 if (selected != NULL) {
1758 selected_path = (GtkTreePath *) selected->data;
1759 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1763 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1764 (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1766 /* Scroll to first path */
1767 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1776 gtk_tree_path_free (start_path);
1778 gtk_tree_path_free (end_path);
1779 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1780 g_list_free (selected);
1782 #endif /* GTK_CHECK_VERSION */
1784 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1791 set_alignment (GtkWidget *widget,
1794 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1795 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1799 create_empty_view (void)
1801 GtkLabel *label = NULL;
1802 GtkWidget *align = NULL;
1804 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1805 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1806 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1807 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1809 return GTK_WIDGET(align);
1813 * Free the returned string
1816 get_gray_color_markup (GtkWidget *styled_widget)
1818 gchar *gray_color_markup = NULL;
1819 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1820 /* Obtain the secondary text color. We need a realized widget, that's why
1821 we get styled_widget from outside */
1823 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1824 gray_color_markup = modest_text_utils_get_color_string (&color);
1825 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1827 if (!gray_color_markup)
1828 gray_color_markup = g_strdup ("#BBBBBB");
1830 return gray_color_markup;
1834 * Free the returned string
1837 create_device_name_visual_string (const gchar *device_name,
1838 const gchar *gray_color_markup)
1842 /* We have to use "" to fill the %s of the translation. We can
1843 not just use the device name because the device name is
1844 shown in a different color, so it could not be included
1845 into the <span> tag */
1846 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1847 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1858 GtkWidget *count_label;
1859 GtkWidget *msg_count_label;
1860 GtkWidget *size_label;
1861 gchar *color_markup;
1865 create_uint_label (const gchar *markup,
1869 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", markup, name, count);
1873 create_gchar_label (const gchar *markup,
1877 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", markup, name, count);
1881 update_folder_stats_status_cb (ModestFolderStats stats,
1884 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1887 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_folders"), stats.folders);
1888 gtk_label_set_markup (GTK_LABEL (widgets->count_label), label);
1891 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_messages"), stats.msg_count);
1892 gtk_label_set_markup (GTK_LABEL (widgets->msg_count_label), label);
1895 if (widgets->size_label) {
1896 tmp = modest_text_utils_get_display_size (stats.local_size);
1897 label = create_gchar_label (widgets->color_markup, _("mcen_fi_rootfolder_size"), tmp);
1898 gtk_label_set_markup (GTK_LABEL (widgets->size_label), label);
1905 update_folder_stats_cb (ModestFolderStats stats,
1908 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1911 update_folder_stats_status_cb (stats, user_data);
1913 /* frees. Note that the widgets could have been destroyed but
1914 we still keep a reference */
1915 g_free (widgets->color_markup);
1916 if (widgets->count_label)
1917 g_object_unref (widgets->count_label);
1918 if (widgets->msg_count_label)
1919 g_object_unref (widgets->msg_count_label);
1920 if (widgets->size_label)
1921 g_object_unref (widgets->size_label);
1922 g_slice_free (DetailsWidgets, widgets);
1926 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1928 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1933 gchar *gray_color_markup;
1934 DetailsWidgets *widgets;
1936 vbox = gtk_vbox_new (FALSE, 0);
1937 widgets = g_slice_new0 (DetailsWidgets);
1939 gray_color_markup = get_gray_color_markup (styled_widget);
1940 widgets->color_markup = g_strdup (gray_color_markup);
1942 /* Account description: */
1943 if (modest_tny_account_is_virtual_local_folders (account)
1944 || (modest_tny_account_is_memory_card_account (account))) {
1946 /* Get device name */
1947 gchar *device_name = NULL;
1948 if (modest_tny_account_is_virtual_local_folders (account))
1949 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1950 MODEST_CONF_DEVICE_NAME, NULL);
1952 device_name = g_strdup (tny_account_get_name (account));
1954 label = create_device_name_visual_string ((const gchar *) device_name,
1955 (const gchar *) gray_color_markup);
1956 label_w = gtk_label_new (NULL);
1957 gtk_label_set_markup (GTK_LABEL (label_w), label);
1958 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1959 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1960 g_free (device_name);
1963 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1964 gtk_box_pack_start (GTK_BOX (vbox),
1965 gtk_label_new (tny_account_get_name (account)),
1968 /* Other accounts, such as IMAP and POP: */
1973 /* Put proto in uppercase */
1974 proto = g_string_new (tny_account_get_proto (account));
1975 proto = g_string_ascii_up (proto);
1977 /* note: mcen_fi_localroot_description is something like "%s account"
1978 * however, we should display "%s account: %s"... therefore, ugly tmp */
1979 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1980 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1981 gray_color_markup, tmp, tny_account_get_name (account));
1984 label_w = gtk_label_new (NULL);
1985 gtk_label_set_markup (GTK_LABEL (label_w), label);
1986 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1987 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1988 g_string_free (proto, TRUE);
1994 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1995 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_messages"), 0);
1996 label_w = gtk_label_new (NULL);
1997 gtk_label_set_markup (GTK_LABEL (label_w), label);
1998 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1999 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2002 widgets->msg_count_label = g_object_ref (label_w);
2005 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_folders"), 0);
2006 label_w = gtk_label_new (NULL);
2007 gtk_label_set_markup (GTK_LABEL (label_w), label);
2008 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2009 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2012 widgets->count_label = g_object_ref (label_w);
2015 if (modest_tny_account_is_virtual_local_folders (account)
2016 || modest_tny_account_is_memory_card_account (account)) {
2018 label = create_gchar_label (gray_color_markup, _("mcen_fi_rootfolder_size"), "0");
2020 label_w = gtk_label_new (NULL);
2021 gtk_label_set_markup (GTK_LABEL (label_w), label);
2022 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2023 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2026 widgets->size_label = g_object_ref (label_w);
2028 } else if (TNY_IS_ACCOUNT(folder_store)) {
2029 TnyAccount *account = TNY_ACCOUNT(folder_store);
2031 time_t last_updated;
2032 const gchar *last_updated_string;
2033 /* Get last updated from configuration */
2034 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
2035 tny_account_get_id (account));
2037 if (last_updated > 0)
2038 last_updated_string = modest_text_utils_get_display_date(last_updated);
2040 last_updated_string = g_strdup (_("mcen_va_never"));
2042 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
2043 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
2044 label_w = gtk_label_new (NULL);
2045 gtk_label_set_markup (GTK_LABEL (label_w), label);
2046 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2047 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2051 g_free (gray_color_markup);
2053 /* Refresh folder stats asynchronously */
2054 modest_tny_folder_store_get_folder_stats (TNY_FOLDER_STORE (account),
2055 update_folder_stats_cb,
2056 update_folder_stats_status_cb,
2060 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
2066 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
2068 ModestMainWindowPrivate *priv = NULL;
2070 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2072 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2074 return priv->send_receive_in_progress;
2078 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
2080 GtkAction *action = NULL;
2081 GtkWidget *widget = NULL;
2082 ModestMainWindowPrivate *priv = NULL;
2084 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2085 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2087 priv->send_receive_in_progress = TRUE;
2089 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2090 gtk_action_set_sensitive (action, FALSE);
2091 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2092 /* gtk_action_set_sensitive (action, FALSE); */
2093 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2094 gtk_widget_set_sensitive (widget, FALSE);
2098 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
2100 GtkAction *action = NULL;
2101 GtkWidget *widget = NULL;
2102 ModestMainWindowPrivate *priv = NULL;
2104 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2105 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2107 priv->send_receive_in_progress = FALSE;
2109 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2110 gtk_action_set_sensitive (action, TRUE);
2111 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2112 /* gtk_action_set_sensitive (action, TRUE); */
2113 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2114 gtk_widget_set_sensitive (widget, TRUE);
2119 on_msg_count_changed (ModestHeaderView *header_view,
2121 TnyFolderChange *change,
2122 ModestMainWindow *main_window)
2124 gboolean refilter = FALSE;
2125 gboolean folder_empty = FALSE;
2126 gboolean all_marked_as_deleted = FALSE;
2127 ModestMainWindowPrivate *priv;
2129 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
2130 g_return_if_fail (TNY_IS_FOLDER(folder));
2131 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2133 if (change != NULL) {
2134 TnyFolderChangeChanged changed;
2136 changed = tny_folder_change_get_changed (change);
2137 /* If something changes */
2138 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
2139 folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
2141 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2143 /* Play a sound (if configured) and make the LED blink */
2144 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
2145 modest_platform_push_email_notification ();
2148 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
2151 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2154 /* Check if all messages are marked to be deleted */
2155 all_marked_as_deleted = modest_header_view_is_empty (header_view);
2156 folder_empty = folder_empty || all_marked_as_deleted;
2158 /* Set contents style of headers view */
2160 modest_main_window_set_contents_style (main_window,
2161 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2162 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
2164 modest_main_window_set_contents_style (main_window,
2165 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2169 modest_header_view_refilter (header_view);
2174 modest_main_window_set_contents_style (ModestMainWindow *self,
2175 ModestMainWindowContentsStyle style)
2177 ModestMainWindowPrivate *priv;
2179 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2181 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2183 /* We allow to set the same content style than the previously
2184 set if there are details, because it could happen when we're
2185 selecting different accounts consecutively */
2186 if ((priv->contents_style == style) &&
2187 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
2190 /* Remove previous child. Delete it if it was an account
2192 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
2194 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
2195 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
2198 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
2201 priv->contents_style = style;
2203 switch (priv->contents_style) {
2204 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
2205 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
2206 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2208 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2209 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
2211 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
2213 /* if we're started without main win, there may not be a folder
2214 * view. this fixes a GLib-Critical */
2215 if (priv->folder_view) {
2216 TnyFolderStore *selected_folderstore =
2217 modest_folder_view_get_selected (priv->folder_view);
2218 if (TNY_IS_ACCOUNT (selected_folderstore)) {
2219 priv->details_widget = create_details_widget (GTK_WIDGET (self),
2220 TNY_ACCOUNT (selected_folderstore));
2222 wrap_in_scrolled_window (priv->contents_widget,
2223 priv->details_widget);
2225 if (selected_folderstore)
2226 g_object_unref (selected_folderstore);
2227 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2230 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2231 gtk_widget_grab_focus (GTK_WIDGET (priv->details_widget));
2234 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
2235 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
2236 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2238 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2239 gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
2242 g_return_if_reached ();
2246 gtk_widget_show_all (priv->contents_widget);
2249 ModestMainWindowContentsStyle
2250 modest_main_window_get_contents_style (ModestMainWindow *self)
2252 ModestMainWindowPrivate *priv;
2254 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
2256 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2257 return priv->contents_style;
2262 on_configuration_key_changed (ModestConf* conf,
2264 ModestConfEvent event,
2265 ModestConfNotificationId id,
2266 ModestMainWindow *self)
2268 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2269 TnyAccount *account = NULL;
2271 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
2274 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
2277 if (priv->folder_view)
2278 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
2280 if (account && TNY_IS_ACCOUNT (account) &&
2281 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
2284 const gchar *device_name;
2285 gchar *new_text, *gray_color_markup;
2288 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
2289 label = GTK_LABEL (children->data);
2291 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2292 MODEST_CONF_DEVICE_NAME, NULL);
2294 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
2295 new_text = create_device_name_visual_string (device_name, gray_color_markup);
2297 gtk_label_set_markup (label, new_text);
2298 gtk_widget_show (GTK_WIDGET (label));
2300 g_free (gray_color_markup);
2302 g_list_free (children);
2304 g_object_unref (account);
2308 set_toolbar_transfer_mode (ModestMainWindow *self)
2310 ModestMainWindowPrivate *priv = NULL;
2312 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2314 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2316 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2318 if (priv->progress_bar_timeout > 0) {
2319 g_source_remove (priv->progress_bar_timeout);
2320 priv->progress_bar_timeout = 0;
2327 set_toolbar_mode (ModestMainWindow *self,
2328 ModestToolBarModes mode)
2330 ModestWindowPrivate *parent_priv = NULL;
2331 ModestMainWindowPrivate *priv = NULL;
2332 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2334 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2336 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2337 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2339 /* In case this was called before the toolbar exists: */
2340 if (!(parent_priv->toolbar))
2343 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2345 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2346 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2347 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2349 /* Sets current toolbar mode */
2350 priv->current_toolbar_mode = mode;
2352 /* Checks the dimming rules */
2353 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2354 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2356 /* Show and hide toolbar items */
2358 case TOOLBAR_MODE_NORMAL:
2360 gtk_action_set_visible (sort_action, TRUE);
2362 gtk_action_set_visible (refresh_action, TRUE);
2363 if (priv->progress_toolitem) {
2364 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2365 gtk_widget_hide (priv->progress_toolitem);
2367 if (priv->progress_bar)
2368 gtk_widget_hide (priv->progress_bar);
2371 gtk_action_set_visible (cancel_action, FALSE);
2373 /* Hide toolbar if optimized view is enabled */
2374 if (priv->optimized_view)
2375 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2377 case TOOLBAR_MODE_TRANSFER:
2379 gtk_action_set_visible (sort_action, FALSE);
2381 gtk_action_set_visible (refresh_action, FALSE);
2383 gtk_action_set_visible (cancel_action, TRUE);
2384 if (priv->progress_bar)
2385 gtk_widget_show (priv->progress_bar);
2386 if (priv->progress_toolitem) {
2387 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2388 gtk_widget_show (priv->progress_toolitem);
2391 /* Show toolbar if it's hiden (optimized view ) */
2392 if (priv->optimized_view)
2393 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2396 g_return_if_reached ();
2401 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2403 ModestMainWindowPrivate *priv;
2405 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2406 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2408 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2412 cancel_progressbar (GtkToolButton *toolbutton,
2413 ModestMainWindow *self)
2416 ModestMainWindowPrivate *priv;
2418 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2420 /* Get operation observers and cancel all the operations */
2421 tmp = priv->progress_widgets;
2423 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2424 tmp=g_slist_next(tmp);
2429 observers_empty (ModestMainWindow *self)
2432 ModestMainWindowPrivate *priv;
2433 gboolean is_empty = TRUE;
2434 guint pending_ops = 0;
2436 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2437 tmp = priv->progress_widgets;
2439 /* Check all observers */
2440 while (tmp && is_empty) {
2441 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2442 is_empty = pending_ops == 0;
2444 tmp = g_slist_next(tmp);
2452 * Gets the toolbar mode needed for each mail operation. It stores in
2453 * @mode_changed if the toolbar mode has changed or not
2455 static ModestToolBarModes
2456 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2457 ModestMailOperation *mail_op,
2458 gboolean *mode_changed)
2460 ModestToolBarModes mode;
2461 ModestMainWindowPrivate *priv;
2463 *mode_changed = FALSE;
2464 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2466 /* Get toolbar mode from operation id*/
2467 switch (modest_mail_operation_get_type_operation (mail_op)) {
2468 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
2469 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2470 mode = TOOLBAR_MODE_TRANSFER;
2471 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2472 *mode_changed = TRUE;
2475 mode = TOOLBAR_MODE_NORMAL;
2481 on_mail_operation_started (ModestMailOperation *mail_op,
2484 ModestMainWindow *self;
2485 ModestMailOperationTypeOperation op_type;
2486 ModestMainWindowPrivate *priv;
2487 ModestToolBarModes mode;
2489 gboolean mode_changed = FALSE;
2490 TnyAccount *account = NULL;
2492 self = MODEST_MAIN_WINDOW (user_data);
2493 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2495 /* Do not show progress for receiving operations if the
2496 account is the local account or the MMC one */
2497 op_type = modest_mail_operation_get_type_operation (mail_op);
2498 account = modest_mail_operation_get_account (mail_op);
2499 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2502 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2503 modest_tny_account_is_memory_card_account (account));
2505 g_object_unref (account);
2509 /* Show information banner. Remove old timeout */
2510 if (priv->opening_banner_timeout > 0) {
2511 g_source_remove (priv->opening_banner_timeout);
2512 priv->opening_banner_timeout = 0;
2514 /* Create a new timeout */
2515 priv->opening_banner_timeout =
2516 g_timeout_add (2000, show_opening_banner, self);
2519 /* Not every mail operation has account, noop does not */
2521 g_object_unref (account);
2523 /* Get toolbar mode from operation id*/
2524 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2526 /* Add operation observers and change toolbar if neccessary*/
2527 tmp = priv->progress_widgets;
2528 if (mode == TOOLBAR_MODE_TRANSFER) {
2530 GObject *source = modest_mail_operation_get_source(mail_op);
2531 if (G_OBJECT (self) == source) {
2532 set_toolbar_transfer_mode(self);
2534 g_object_unref (source);
2538 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2540 tmp = g_slist_next (tmp);
2544 /* Update the main menu as well, we need to explicitely do
2545 this in order to enable/disable accelerators */
2546 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2550 on_mail_operation_finished (ModestMailOperation *mail_op,
2553 ModestToolBarModes mode;
2554 ModestMailOperationTypeOperation op_type;
2556 ModestMainWindow *self;
2557 gboolean mode_changed;
2558 TnyAccount *account = NULL;
2559 ModestMainWindowPrivate *priv;
2561 self = MODEST_MAIN_WINDOW (user_data);
2562 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2564 /* The mail operation was not added to the progress objects if
2565 the account was the local account or the MMC one */
2566 op_type = modest_mail_operation_get_type_operation (mail_op);
2567 account = modest_mail_operation_get_account (mail_op);
2568 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2571 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2572 modest_tny_account_is_memory_card_account (account));
2574 g_object_unref (account);
2578 /* Remove old timeout */
2579 if (priv->opening_banner_timeout > 0) {
2580 g_source_remove (priv->opening_banner_timeout);
2581 priv->opening_banner_timeout = 0;
2584 /* Remove the banner if exists */
2585 if (priv->opening_banner) {
2586 gtk_widget_destroy (priv->opening_banner);
2587 priv->opening_banner = NULL;
2591 /* Not every mail operation has account, noop does not */
2593 g_object_unref (account);
2595 /* Get toolbar mode from operation id*/
2596 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2598 /* Change toolbar mode */
2599 tmp = priv->progress_widgets;
2600 if (mode == TOOLBAR_MODE_TRANSFER) {
2602 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2604 tmp = g_slist_next (tmp);
2607 /* If no more operations are being observed, NORMAL mode is enabled again */
2608 if (observers_empty (self)) {
2609 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2615 on_queue_changed (ModestMailOperationQueue *queue,
2616 ModestMailOperation *mail_op,
2617 ModestMailOperationQueueNotification type,
2618 ModestMainWindow *self)
2620 ModestMainWindowPrivate *priv;
2622 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2624 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2625 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2627 "operation-started",
2628 G_CALLBACK (on_mail_operation_started),
2630 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2632 "operation-finished",
2633 G_CALLBACK (on_mail_operation_finished),
2635 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2636 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2638 "operation-started");
2639 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2641 "operation-finished");
2646 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2648 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2650 ModestAccountMgr *mgr;
2651 ModestAccountSettings *settings;
2652 ModestServerAccountSettings *store_settings = NULL;
2654 /* Get account data */
2655 mgr = modest_runtime_get_account_mgr ();
2656 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2658 store_settings = modest_account_settings_get_store_settings (settings);
2660 /* Set the new visible & active account */
2661 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2662 const gchar *account_name;
2664 account_name = modest_account_settings_get_account_name (settings);
2666 modest_folder_view_set_account_id_of_visible_server_account
2668 modest_server_account_settings_get_account_name (store_settings));
2669 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2670 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2672 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2673 if (action != NULL) {
2674 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2675 modest_utils_toggle_action_set_active_block_notify (
2676 GTK_TOGGLE_ACTION (action),
2684 g_object_unref (store_settings);
2685 g_object_unref (settings);
2689 /* Make sure that at least one account is "viewed": */
2691 set_at_least_one_account_visible(ModestMainWindow *self)
2693 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2694 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2696 if (!(priv->folder_view)) {
2697 /* It is too early to do this. */
2701 const gchar *active_server_account_name =
2702 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2704 if (!active_server_account_name ||
2705 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2707 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2708 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2709 if (default_modest_name) {
2710 set_account_visible (self, default_modest_name);
2711 } else if (first_modest_name) {
2712 set_account_visible (self, first_modest_name);
2714 g_free (first_modest_name);
2715 g_free (default_modest_name);
2720 on_show_account_action_toggled (GtkToggleAction *action,
2723 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2725 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2726 if (gtk_toggle_action_get_active (action))
2727 set_account_visible (self, acc_name);
2731 refresh_account (const gchar *account_name)
2735 /* win must already exists here, obviously */
2736 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2739 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2743 /* If account_name == NULL, we must update all (option All) */
2745 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2747 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2752 on_refresh_account_action_activated (GtkAction *action,
2755 refresh_account ((const gchar*) user_data);
2759 on_send_receive_csm_activated (GtkMenuItem *item,
2762 refresh_account ((const gchar*) user_data);
2766 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2768 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2770 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2776 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2778 ModestMainWindow *main_window = NULL;
2780 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2781 main_window = MODEST_MAIN_WINDOW (userdata);
2783 /* Update toolbar dimming state */
2784 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2785 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2791 on_header_view_focus_in (GtkWidget *widget,
2792 GdkEventFocus *event,
2795 ModestMainWindow *main_window = NULL;
2797 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2799 main_window = MODEST_MAIN_WINDOW (userdata);
2801 /* Update toolbar dimming state */
2802 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2803 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2809 on_folder_selection_changed (ModestFolderView *folder_view,
2810 TnyFolderStore *folder_store,
2812 ModestMainWindow *main_window)
2814 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2815 GtkAction *action = NULL;
2816 gboolean show_reply = TRUE;
2817 gboolean show_forward = TRUE;
2818 gboolean show_cancel_send = FALSE;
2819 gboolean show_clipboard = TRUE;
2820 gboolean show_delete = TRUE;
2823 if (TNY_IS_ACCOUNT (folder_store)) {
2824 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2825 } else if (TNY_IS_FOLDER (folder_store)) {
2826 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2827 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2828 TNY_FOLDER (folder_store));
2829 switch (folder_type) {
2830 case TNY_FOLDER_TYPE_DRAFTS:
2831 show_clipboard = show_delete = TRUE;
2832 show_reply = show_forward = show_cancel_send = FALSE;
2834 case TNY_FOLDER_TYPE_SENT:
2835 show_forward = show_clipboard = show_delete = TRUE;
2836 show_reply = show_cancel_send = FALSE;
2838 case TNY_FOLDER_TYPE_OUTBOX:
2839 show_clipboard = show_delete = show_cancel_send = TRUE;
2840 show_reply = show_forward = FALSE;
2842 case TNY_FOLDER_TYPE_INVALID:
2843 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2846 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2847 show_cancel_send = FALSE;
2850 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2851 show_cancel_send = FALSE;
2856 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2857 gtk_action_set_visible (action, show_reply);
2858 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2859 gtk_action_set_visible (action, show_reply);
2860 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2861 gtk_action_set_visible (action, show_forward);
2862 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2863 gtk_action_set_visible (action, show_cancel_send);
2864 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2865 gtk_action_set_visible (action, show_delete);
2867 /* We finally call to the ui actions handler, after updating properly
2868 * the header view CSM */
2869 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2873 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2874 GtkTreeModel *model,
2875 GtkTreeRowReference *row_reference,
2876 ModestMainWindow *self)
2878 ModestMainWindowPrivate *priv = NULL;
2879 GtkTreeModel *header_model = NULL;
2880 GtkTreePath *path = NULL;
2882 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2883 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2884 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2886 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2887 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2889 /* Do nothing if we changed the folder in the main view */
2890 if (header_model != model)
2893 /* Select the message in the header view */
2894 path = gtk_tree_row_reference_get_path (row_reference);
2895 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2897 gtk_tree_path_free (path);
2903 updating_banner_destroyed (gpointer data,
2904 GObject *where_the_object_was)
2906 ModestMainWindowPrivate *priv = NULL;
2908 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2910 priv->updating_banner = NULL;
2914 show_updating_banner (gpointer user_data)
2916 ModestMainWindowPrivate *priv = NULL;
2918 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2920 if (priv->updating_banner == NULL) {
2922 /* We're outside the main lock */
2923 gdk_threads_enter ();
2924 priv->updating_banner =
2925 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2926 _CS ("ckdg_pb_updating"));
2928 /* We need this because banners in Maemo could be
2929 destroyed by dialogs so we need to properly update
2930 our reference to it */
2931 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2932 updating_banner_destroyed,
2934 gdk_threads_leave ();
2937 /* Remove timeout */
2938 priv->updating_banner_timeout = 0;
2943 * We use this function to show/hide a progress banner showing
2944 * "Updating" while the header view is being filled. We're not showing
2945 * it unless the update takes more than 2 seconds
2947 * If starting = TRUE then the refresh is starting, otherwise it means
2948 * that is has just finished
2951 on_updating_msg_list (ModestHeaderView *header_view,
2955 ModestMainWindowPrivate *priv = NULL;
2957 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2959 /* Remove old timeout */
2960 if (priv->updating_banner_timeout > 0) {
2961 g_source_remove (priv->updating_banner_timeout);
2962 priv->updating_banner_timeout = 0;
2965 /* Create a new timeout */
2967 priv->updating_banner_timeout =
2968 g_timeout_add (2000, show_updating_banner, user_data);
2970 /* Remove the banner if exists */
2971 if (priv->updating_banner) {
2972 gtk_widget_destroy (priv->updating_banner);
2973 priv->updating_banner = NULL;
2979 modest_main_window_screen_is_on (ModestMainWindow *self)
2981 ModestMainWindowPrivate *priv = NULL;
2983 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2985 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2987 return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2991 remove_banners (ModestMainWindow *window)
2993 ModestMainWindowPrivate *priv;
2995 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2997 if (priv->opening_banner_timeout > 0) {
2998 g_source_remove (priv->opening_banner_timeout);
2999 priv->opening_banner_timeout = 0;
3002 if (priv->opening_banner != NULL) {
3003 gtk_widget_destroy (priv->opening_banner);
3004 priv->opening_banner = NULL;
3007 if (priv->updating_banner_timeout > 0) {
3008 g_source_remove (priv->updating_banner_timeout);
3009 priv->updating_banner_timeout = 0;
3012 if (priv->updating_banner != NULL) {
3013 gtk_widget_destroy (priv->updating_banner);
3014 priv->updating_banner = NULL;
3020 on_window_hide (GObject *gobject,
3024 g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
3026 if (!GTK_WIDGET_VISIBLE (gobject)) {
3027 TnyFolderStore *folder_store;
3028 ModestMainWindowPrivate *priv;
3030 /* Remove the currently shown banners */
3031 remove_banners (MODEST_MAIN_WINDOW (gobject));
3033 /* Force the folder view to sync the currently selected folder
3034 to save the read/unread status and to expunge messages */
3035 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
3036 folder_store = modest_folder_view_get_selected (priv->folder_view);
3037 if (TNY_IS_FOLDER (folder_store)) {
3038 ModestMailOperation *mail_op;
3040 mail_op = modest_mail_operation_new (NULL);
3041 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3043 modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
3044 g_object_unref (mail_op);
3045 g_object_unref (folder_store);
3051 on_window_destroy (GtkObject *widget,
3054 g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
3056 remove_banners (MODEST_MAIN_WINDOW (widget));
3060 opening_banner_destroyed (gpointer data,
3061 GObject *where_the_object_was)
3063 ModestMainWindowPrivate *priv = NULL;
3065 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
3067 priv->opening_banner = NULL;
3071 show_opening_banner (gpointer user_data)
3073 ModestMainWindowPrivate *priv = NULL;
3075 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
3077 if (priv->opening_banner == NULL) {
3079 /* We're outside the main lock */
3080 gdk_threads_enter ();
3081 priv->opening_banner =
3082 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
3083 _("mail_me_opening"));
3085 /* We need this because banners in Maemo could be
3086 destroyed by dialogs so we need to properly update
3087 our reference to it */
3088 g_object_weak_ref (G_OBJECT (priv->opening_banner),
3089 opening_banner_destroyed,
3092 /* We need this because banners in Maemo could be
3093 destroyed by dialogs so we need to properly update
3094 our reference to it */
3095 g_object_weak_ref (G_OBJECT (priv->updating_banner),
3096 updating_banner_destroyed,
3098 gdk_threads_leave ();
3101 /* Remove timeout */
3102 priv->opening_banner_timeout = 0;