1 /* Copyright (c) 2006, y2008 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"
67 #include <tny-gtk-folder-store-tree-model.h>
69 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
76 /* 'private'/'protected' functions */
77 static void modest_main_window_class_init (ModestMainWindowClass *klass);
78 static void modest_main_window_init (ModestMainWindow *obj);
79 static void modest_main_window_finalize (GObject *obj);
81 static void connect_signals (ModestMainWindow *self);
83 static void modest_main_window_disconnect_signals (ModestWindow *self);
85 static void restore_settings (ModestMainWindow *self,
86 gboolean do_folder_view_too);
88 static void save_state (ModestWindow *self);
90 static void update_menus (ModestMainWindow* self);
92 static void modest_main_window_show_toolbar (ModestWindow *window,
93 gboolean show_toolbar);
95 static void cancel_progressbar (GtkToolButton *toolbutton,
96 ModestMainWindow *self);
98 static void on_queue_changed (ModestMailOperationQueue *queue,
99 ModestMailOperation *mail_op,
100 ModestMailOperationQueueNotification type,
101 ModestMainWindow *self);
103 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
105 static void on_account_inserted (TnyAccountStore *accoust_store,
109 static void on_account_removed (TnyAccountStore *accoust_store,
113 static void on_account_changed (TnyAccountStore *account_store,
117 static void on_default_account_changed (ModestAccountMgr* mgr,
120 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
124 static void on_configuration_key_changed (ModestConf* conf,
126 ModestConfEvent event,
127 ModestConfNotificationId id,
128 ModestMainWindow *self);
130 static void set_toolbar_mode (ModestMainWindow *self,
131 ModestToolBarModes mode);
133 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
135 static void on_show_account_action_toggled (GtkToggleAction *action,
138 static void on_refresh_account_action_activated (GtkAction *action,
141 static void on_send_receive_csm_activated (GtkMenuItem *item,
144 static void on_folder_view_row_activated (GtkTreeView *tree_view,
145 GtkTreePath *tree_path,
146 GtkTreeViewColumn *column,
148 static void on_msg_count_changed (ModestHeaderView *header_view,
150 TnyFolderChange *change,
151 ModestMainWindow *main_window);
153 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
156 static GtkWidget * create_empty_view (void);
158 static gboolean on_folder_view_focus_in (GtkWidget *widget,
159 GdkEventFocus *event,
162 static gboolean on_header_view_focus_in (GtkWidget *widget,
163 GdkEventFocus *event,
166 static void on_folder_selection_changed (ModestFolderView *folder_view,
167 TnyFolderStore *folder_store,
169 ModestMainWindow *main_window);
171 static void set_at_least_one_account_visible(ModestMainWindow *self);
173 static void on_updating_msg_list (ModestHeaderView *header_view,
177 static gboolean show_opening_banner (gpointer user_data);
179 static void on_window_destroy (GtkObject *widget,
182 static void on_window_hide (GObject *gobject,
186 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
187 struct _ModestMainWindowPrivate {
188 GtkWidget *main_vbox;
189 GtkWidget *contents_widget;
190 GtkWidget *empty_view;
192 /* Progress observers */
193 GtkWidget *progress_bar;
194 GSList *progress_widgets;
197 GtkWidget *progress_toolitem;
198 GtkWidget *cancel_toolitem;
199 GtkWidget *sort_toolitem;
200 GtkWidget *refresh_toolitem;
201 ModestToolBarModes current_toolbar_mode;
203 /* Merge ids used to add/remove accounts to the Accounts Menu*/
204 GByteArray *merge_ids;
205 GtkActionGroup *view_additions_group;
207 /* On-demand widgets */
208 GtkWidget *accounts_popup;
209 GtkWidget *details_widget;
211 /* Optimized view enabled */
212 gboolean optimized_view;
214 /* Optimized view enabled */
215 gboolean send_receive_in_progress;
217 ModestHeaderView *header_view;
218 ModestFolderView *folder_view;
220 ModestMainWindowStyle style;
221 ModestMainWindowContentsStyle contents_style;
222 gboolean wait_for_settings;
224 guint progress_bar_timeout;
226 /* Signal handler UIDs */
227 GList *queue_err_signals;
230 /* "Updating" banner for header view */
231 GtkWidget *updating_banner;
232 guint updating_banner_timeout;
234 /* "Opening" banner for header view */
235 GtkWidget *opening_banner;
236 guint opening_banner_timeout;
239 osso_display_state_t display_state;
241 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
242 MODEST_TYPE_MAIN_WINDOW, \
243 ModestMainWindowPrivate))
245 typedef struct _GetMsgAsyncHelper {
246 ModestMainWindowPrivate *main_window_private;
248 ModestTnyMsgReplyType reply_type;
249 ModestTnyMsgForwardType forward_type;
256 static GtkWindowClass *parent_class = NULL;
259 /* Private actions */
260 /* This is the context sensitive menu: */
261 static const GtkActionEntry modest_folder_view_action_entries [] = {
263 /* Folder View CSM actions */
264 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
265 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
266 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
267 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
270 static const GtkActionEntry modest_header_view_action_entries [] = {
272 /* Header View CSM actions */
273 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
274 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
275 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
276 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
277 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
278 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
279 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
280 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
281 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
284 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
285 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
288 /************************************************************************/
291 modest_main_window_get_type (void)
293 static GType my_type = 0;
295 static const GTypeInfo my_info = {
296 sizeof(ModestMainWindowClass),
297 NULL, /* base init */
298 NULL, /* base finalize */
299 (GClassInitFunc) modest_main_window_class_init,
300 NULL, /* class finalize */
301 NULL, /* class data */
302 sizeof(ModestMainWindow),
304 (GInstanceInitFunc) modest_main_window_init,
307 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
315 modest_main_window_class_init (ModestMainWindowClass *klass)
317 GObjectClass *gobject_class;
318 gobject_class = (GObjectClass*) klass;
319 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
321 parent_class = g_type_class_peek_parent (klass);
322 gobject_class->finalize = modest_main_window_finalize;
324 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
326 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
327 modest_window_class->save_state_func = save_state;
328 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
329 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
330 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
334 modest_main_window_init (ModestMainWindow *obj)
336 ModestMainWindowPrivate *priv;
338 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
340 priv->queue_err_signals = NULL;
341 priv->main_vbox = NULL;
342 priv->header_view = NULL;
343 priv->folder_view = NULL;
344 priv->contents_widget = NULL;
345 priv->accounts_popup = NULL;
346 priv->details_widget = NULL;
347 priv->empty_view = NULL;
348 priv->progress_widgets = NULL;
349 priv->progress_bar = NULL;
350 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
351 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
352 priv->wait_for_settings = TRUE;
353 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
354 priv->merge_ids = NULL;
355 priv->optimized_view = FALSE;
356 priv->send_receive_in_progress = FALSE;
357 priv->progress_bar_timeout = 0;
358 priv->sighandlers = NULL;
359 priv->updating_banner = NULL;
360 priv->updating_banner_timeout = 0;
361 priv->opening_banner = NULL;
362 priv->opening_banner_timeout = 0;
363 priv->display_state = OSSO_DISPLAY_ON;
365 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
367 "applications_email_mainview");
371 modest_main_window_finalize (GObject *obj)
373 ModestMainWindowPrivate *priv;
375 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
377 /* Sanity check: shouldn't be needed, the window mgr should
378 call this function before */
379 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
380 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
382 if (priv->empty_view) {
383 g_object_unref (priv->empty_view);
384 priv->empty_view = NULL;
387 if (priv->header_view) {
388 g_object_unref (priv->header_view);
389 priv->header_view = NULL;
392 g_slist_free (priv->progress_widgets);
394 g_byte_array_free (priv->merge_ids, TRUE);
396 if (priv->progress_bar_timeout > 0) {
397 g_source_remove (priv->progress_bar_timeout);
398 priv->progress_bar_timeout = 0;
401 if (priv->updating_banner_timeout > 0) {
402 g_source_remove (priv->updating_banner_timeout);
403 priv->updating_banner_timeout = 0;
406 if (priv->updating_banner) {
407 gtk_widget_destroy (priv->updating_banner);
408 priv->updating_banner = NULL;
411 if (priv->opening_banner_timeout > 0) {
412 g_source_remove (priv->opening_banner_timeout);
413 priv->opening_banner_timeout = 0;
416 if (priv->opening_banner) {
417 gtk_widget_destroy (priv->opening_banner);
418 priv->opening_banner = NULL;
421 G_OBJECT_CLASS(parent_class)->finalize (obj);
425 modest_main_window_get_child_widget (ModestMainWindow *self,
426 ModestMainWindowWidgetType widget_type)
428 ModestMainWindowPrivate *priv;
431 g_return_val_if_fail (self && MODEST_IS_MAIN_WINDOW(self), NULL);
432 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
435 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
437 switch (widget_type) {
438 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
439 widget = (GtkWidget*)priv->header_view; break;
440 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
441 widget = (GtkWidget*)priv->folder_view; break;
446 /* Note that the window could have been destroyed, and so
447 their children, but still have some references */
448 return (widget && GTK_IS_WIDGET(widget)) ? GTK_WIDGET(widget) : NULL;
453 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
456 ModestMainWindowPrivate *priv;
458 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
460 conf = modest_runtime_get_conf ();
462 modest_widget_memory_restore (conf, G_OBJECT(self),
463 MODEST_CONF_MAIN_WINDOW_KEY);
465 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
466 MODEST_CONF_HEADER_VIEW_KEY);
468 if (do_folder_view_too)
469 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
470 MODEST_CONF_FOLDER_VIEW_KEY);
472 gtk_widget_show (GTK_WIDGET (self));
477 save_state (ModestWindow *window)
480 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
481 ModestMainWindowPrivate *priv;
483 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
484 conf = modest_runtime_get_conf ();
486 modest_widget_memory_save (conf,G_OBJECT(self),
487 MODEST_CONF_MAIN_WINDOW_KEY);
488 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
489 MODEST_CONF_FOLDER_VIEW_KEY);
493 compare_display_names (ModestAccountSettings *a,
494 ModestAccountSettings *b)
496 return g_utf8_collate (modest_account_settings_get_display_name (a),
497 modest_account_settings_get_display_name (b));
501 /* We use this function to prevent the send&receive CSM to be shown
502 when there are less than two account */
504 tap_and_hold_query_cb (GtkWidget *widget, GdkEvent *event)
510 update_menus (ModestMainWindow* self)
512 GSList *account_names, *iter, *accounts;
513 ModestMainWindowPrivate *priv;
514 ModestWindowPrivate *parent_priv;
515 ModestAccountMgr *mgr;
516 gint i, num_accounts;
518 gchar *default_account;
519 const gchar *active_account_name;
520 GtkWidget *send_receive_button, *item;
521 GtkAction *send_receive_all = NULL;
524 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
525 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
527 /* Get enabled account IDs */
528 mgr = modest_runtime_get_account_mgr ();
529 account_names = modest_account_mgr_account_names (mgr, TRUE);
530 iter = account_names;
534 ModestAccountSettings *settings =
535 modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
536 accounts = g_slist_prepend (accounts, settings);
540 modest_account_mgr_free_account_names (account_names);
541 account_names = NULL;
543 /* Order the list of accounts by its display name */
544 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
545 num_accounts = g_slist_length (accounts);
547 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
548 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
549 gtk_action_set_visible (send_receive_all, num_accounts > 0);
551 /* Delete old send&receive popup items. We can not just do a
552 menu_detach because it does not work well with
554 if (priv->accounts_popup)
555 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
556 (GtkCallback) gtk_widget_destroy, NULL);
558 /* Delete old entries in the View menu. Do not free groups, it
560 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
562 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
563 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
564 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
565 GTK_ACTION_GROUP (groups->data));
568 if (priv->merge_ids) {
569 for (i = 0; i < priv->merge_ids->len; i++)
570 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
571 g_byte_array_free (priv->merge_ids, TRUE);
573 /* We need to call this in order to ensure
574 that the new actions are added in the right
575 order (alphabetical) */
576 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
578 groups = g_list_next (groups);
580 priv->merge_ids = g_byte_array_sized_new (num_accounts);
582 /* Get send receive button */
583 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
584 "/ToolBar/ToolbarSendReceive");
586 /* Create the menu */
587 if (num_accounts > 1) {
588 if (!priv->accounts_popup)
589 priv->accounts_popup = gtk_menu_new ();
590 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
591 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
592 g_signal_connect (G_OBJECT (item),
594 G_CALLBACK (on_send_receive_csm_activated),
596 item = gtk_separator_menu_item_new ();
597 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
600 /* Create a new action group */
601 default_account = modest_account_mgr_get_default_account (mgr);
602 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
604 if (!active_account_name)
605 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
607 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
609 for (i = 0; i < num_accounts; i++) {
610 gchar *display_name = NULL;
611 const gchar *account_name;
612 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
615 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
618 account_name = modest_account_settings_get_account_name (settings);
620 if (default_account && account_name &&
621 !(strcmp (default_account, account_name) == 0)) {
622 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
623 modest_account_settings_get_display_name (settings));
625 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
626 modest_account_settings_get_display_name (settings));
631 /* Create action and add it to the action group. The
632 action name must be the account name, this way we
633 could know in the handlers the account to show */
634 if (settings && account_name) {
635 gchar* item_name, *refresh_action_name;
637 GtkAction *view_account_action, *refresh_account_action;
638 gchar *escaped_display_name;
640 escaped_display_name = modest_text_utils_escape_mnemonics (display_name);
642 view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
643 escaped_display_name, NULL, NULL, 0));
644 g_free (escaped_display_name);
645 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
646 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
647 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
649 if (active_account_name) {
650 if (active_account_name && account_name &&
651 (strcmp (active_account_name, account_name) == 0)) {
652 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
656 /* Add ui from account data. We allow 2^9-1 account
657 changes in a single execution because we're
658 downcasting the guint to a guint8 in order to use a
659 GByteArray. It should be enough :-) */
660 item_name = g_strconcat (account_name, "Menu", NULL);
661 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
662 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
663 gtk_ui_manager_add_ui (parent_priv->ui_manager,
665 "/MenuBar/AccountsMenu/AccountsMenuAdditions",
668 GTK_UI_MANAGER_MENUITEM,
671 /* Connect the action signal "activate" */
672 g_signal_connect_after (G_OBJECT (view_account_action),
674 G_CALLBACK (on_show_account_action_toggled),
677 /* Create the items for the Tools->Send&Receive submenu */
678 refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
679 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
680 display_name, NULL, NULL);
681 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
683 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
684 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
685 gtk_ui_manager_add_ui (parent_priv->ui_manager,
687 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
690 GTK_UI_MANAGER_MENUITEM,
692 g_free (refresh_action_name);
694 g_signal_connect_data (G_OBJECT (refresh_account_action),
696 G_CALLBACK (on_refresh_account_action_activated),
697 g_strdup (account_name),
698 (GClosureNotify) g_free,
701 /* Create item and add it to the send&receive
702 CSM. If there is only one account then
704 if (num_accounts > 1) {
705 GtkWidget *label = gtk_label_new(NULL);
706 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
707 if (default_account && (strcmp(account_name, default_account) == 0)) {
708 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
709 gtk_label_set_markup (GTK_LABEL (label), escaped);
712 gtk_label_set_text (GTK_LABEL (label), display_name);
715 item = gtk_menu_item_new ();
716 gtk_container_add (GTK_CONTAINER (item), label);
718 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup),
720 g_signal_connect_data (G_OBJECT (item),
722 G_CALLBACK (on_send_receive_csm_activated),
723 g_strdup (account_name),
724 (GClosureNotify) g_free,
731 g_free (display_name);
734 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
736 /* We cannot do this in the loop above because this relies on the action
737 * group being inserted. This makes the default account appear in bold.
738 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
739 for (i = 0; i < num_accounts; i++) {
740 gchar *item_name, *path;
742 ModestAccountSettings *settings;
743 const gchar *account_name;
746 settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
747 account_name = modest_account_settings_get_account_name (settings);
748 is_default = (account_name && default_account && !strcmp (account_name, default_account));
750 /* Get the item of the view menu */
751 item_name = g_strconcat (account_name, "Menu", NULL);
752 path = g_strconcat ("/MenuBar/AccountsMenu/AccountsMenuAdditions/", item_name, NULL);
753 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
757 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
758 if (GTK_IS_LABEL (child)) {
759 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
761 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
762 gtk_label_set_markup (GTK_LABEL (child), bold_name);
768 /* Get the item of the tools menu */
769 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
770 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
774 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
775 if (GTK_IS_LABEL (child)) {
776 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
778 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
779 gtk_label_set_markup (GTK_LABEL (child), bold_name);
782 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
787 g_object_unref (settings);
790 if (num_accounts > 1) {
791 /* Disconnect the tap-and-hold-query if it's connected */
792 if (modest_signal_mgr_is_connected (priv->sighandlers,
793 G_OBJECT (send_receive_button),
794 "tap-and-hold-query"))
795 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
796 G_OBJECT (send_receive_button),
797 "tap-and-hold-query");
799 /* Mandatory in order to view the menu contents */
800 gtk_widget_show_all (priv->accounts_popup);
802 /* Setup tap_and_hold just if was not done before*/
803 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
804 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
806 /* Connect the tap-and-hold-query in order not to show the CSM */
807 if (!modest_signal_mgr_is_connected (priv->sighandlers,
808 G_OBJECT (send_receive_button),
809 "tap-and-hold-query"))
810 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
811 G_OBJECT (send_receive_button),
812 "tap-and-hold-query",
813 G_CALLBACK (tap_and_hold_query_cb),
818 g_slist_free (accounts);
819 g_free (default_account);
822 /* Make sure that at least one account is viewed if there are any
823 * accounts, for instance when adding the first account: */
824 set_at_least_one_account_visible (self);
828 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
830 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
831 gtk_scrolled_window_add_with_viewport
832 (GTK_SCROLLED_WINDOW(win), widget);
834 gtk_container_add (GTK_CONTAINER(win),
845 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
847 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
849 GList *oerrsignals = priv->queue_err_signals;
850 while (oerrsignals) {
851 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
852 g_signal_handler_disconnect (esignal->queue, esignal->signal);
853 g_slice_free (QueueErrorSignal, esignal);
854 oerrsignals = g_list_next (oerrsignals);
856 g_list_free (priv->queue_err_signals);
857 priv->queue_err_signals = NULL;
862 modest_main_window_disconnect_signals (ModestWindow *self)
864 ModestMainWindowPrivate *priv;
865 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
867 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
868 priv->sighandlers = NULL;
872 connect_signals (ModestMainWindow *self)
874 ModestWindowPrivate *parent_priv;
875 ModestMainWindowPrivate *priv;
877 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
878 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
883 modest_signal_mgr_connect (priv->sighandlers,
884 G_OBJECT(priv->folder_view), "key-press-event",
885 G_CALLBACK(on_inner_widgets_key_pressed), self);
887 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
888 "folder_selection_changed",
889 G_CALLBACK (on_folder_selection_changed),
892 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
893 "folder-display-name-changed",
894 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
897 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
899 G_CALLBACK (on_folder_view_focus_in),
902 /* Folder view CSM */
903 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
904 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
905 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
906 G_CALLBACK(_folder_view_csm_menu_activated),
909 /* folder view row activated */
910 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "row-activated",
911 G_CALLBACK(on_folder_view_row_activated),
916 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
917 G_CALLBACK(modest_ui_actions_on_header_selected), self);
919 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
920 G_CALLBACK(modest_ui_actions_on_header_activated), self);
922 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
923 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
925 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
926 G_CALLBACK(on_inner_widgets_key_pressed), self);
928 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
929 G_CALLBACK(on_msg_count_changed), self);
931 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
932 G_CALLBACK (on_header_view_focus_in), self);
934 modest_signal_mgr_connect (priv->sighandlers,
935 G_OBJECT (priv->header_view),
937 G_CALLBACK (on_updating_msg_list),
941 /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
942 * in destroy stage */
943 g_signal_connect (G_OBJECT (self), "destroy", G_CALLBACK (on_window_destroy), NULL);
945 g_signal_connect (G_OBJECT (self), "notify::visible", G_CALLBACK (on_window_hide), NULL);
947 /* Mail Operation Queue */
949 modest_signal_mgr_connect (priv->sighandlers,
950 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
952 G_CALLBACK (on_queue_changed), self);
954 /* Track changes in the device name */
956 modest_signal_mgr_connect (priv->sighandlers,
957 G_OBJECT(modest_runtime_get_conf ()),
959 G_CALLBACK (on_configuration_key_changed),
962 /* Track account changes. We need to refresh the toolbar */
964 modest_signal_mgr_connect (priv->sighandlers,
965 G_OBJECT (modest_runtime_get_account_store ()),
967 G_CALLBACK (on_account_inserted),
970 modest_signal_mgr_connect (priv->sighandlers,
971 G_OBJECT (modest_runtime_get_account_store ()),
973 G_CALLBACK (on_account_removed),
976 /* We need to refresh the send & receive menu to change the bold
977 * account when the default account changes. */
979 modest_signal_mgr_connect (priv->sighandlers,
980 G_OBJECT (modest_runtime_get_account_mgr ()),
981 "default_account_changed",
982 G_CALLBACK (on_default_account_changed),
987 modest_signal_mgr_connect (priv->sighandlers,
988 G_OBJECT (modest_runtime_get_account_store ()),
990 G_CALLBACK (on_account_changed),
995 on_hildon_program_is_topmost_notify(GObject *self,
996 GParamSpec *propert_param,
999 HildonProgram *app = HILDON_PROGRAM (self);
1001 /* Note that use of hildon_program_set_can_hibernate()
1002 * is generally referred to as "setting the killable flag",
1003 * though hibernation does not seem equal to death.
1006 if (hildon_program_get_is_topmost (app)) {
1007 /* Prevent hibernation when the progam comes to the foreground,
1008 * because hibernation should only happen when the application
1009 * is in the background: */
1010 hildon_program_set_can_hibernate (app, FALSE);
1012 /* Remove new mail visual notifications */
1013 modest_platform_remove_new_mail_notifications (TRUE);
1015 /* Allow hibernation if the program has gone to the background: */
1017 /* However, prevent hibernation while the settings are being changed: */
1018 const gboolean hibernation_prevented =
1019 modest_window_mgr_get_hibernation_is_prevented (
1020 modest_runtime_get_window_mgr ());
1022 if (hibernation_prevented)
1023 hildon_program_set_can_hibernate (app, FALSE);
1025 /* Allow hibernation, after saving the state: */
1026 modest_osso_save_state();
1027 hildon_program_set_can_hibernate (app, TRUE);
1038 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1040 ShowHelper *helper = (ShowHelper *) user_data;
1041 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1043 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1044 modest_main_window_set_contents_style (MODEST_MAIN_WINDOW (self),
1045 MODEST_MAIN_WINDOW_CONTENTS_STYLE_FOLDERS);
1046 gtk_tree_view_expand_all (GTK_TREE_VIEW (priv->folder_view));
1048 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1050 /* Connect signals */
1051 connect_signals (MODEST_MAIN_WINDOW (self));
1053 /* Set account store */
1054 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1055 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1057 /* Load previous osso state, for instance if we are being restored from
1059 modest_osso_load_state ();
1061 /* Restore window & widget settings */
1062 priv->wait_for_settings = TRUE;
1063 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1064 priv->wait_for_settings = FALSE;
1066 /* Check if accounts exist and show the account wizard if not */
1067 gboolean accounts_exist =
1068 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1070 if (!accounts_exist) {
1071 /* This is necessary to have the main window shown behind the dialog
1072 It's an ugly hack... jschmid */
1073 gtk_widget_show_all(GTK_WIDGET(self));
1074 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1076 update_menus (MODEST_MAIN_WINDOW (self));
1079 /* Never call this function again (NOTE that it could happen
1080 as we hide the main window instead of closing it while
1081 there are operations ongoing) and free the helper */
1082 g_signal_handler_disconnect (self, helper->handler_id);
1083 g_slice_free (ShowHelper, helper);
1087 osso_display_event_cb (osso_display_state_t state,
1090 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1092 priv->display_state = state;
1094 /* Stop blinking if the screen becomes on */
1095 if (priv->display_state == OSSO_DISPLAY_ON)
1096 modest_platform_remove_new_mail_notifications (TRUE);
1100 modest_main_window_new (void)
1102 ModestMainWindow *self = NULL;
1103 ModestMainWindowPrivate *priv = NULL;
1104 ModestWindowPrivate *parent_priv = NULL;
1105 ModestDimmingRulesGroup *menu_rules_group = NULL;
1106 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1107 GtkActionGroup *action_group = NULL;
1108 GError *error = NULL;
1110 GdkPixbuf *window_icon;
1113 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1114 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1115 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1117 parent_priv->ui_manager = gtk_ui_manager_new();
1118 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1120 action_group = gtk_action_group_new ("ModestMainWindowActions");
1121 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1123 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1124 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1126 /* Add common actions */
1127 gtk_action_group_add_actions (action_group,
1128 modest_action_entries,
1129 G_N_ELEMENTS (modest_action_entries),
1132 gtk_action_group_add_actions (action_group,
1133 modest_folder_view_action_entries,
1134 G_N_ELEMENTS (modest_folder_view_action_entries),
1137 gtk_action_group_add_actions (action_group,
1138 modest_header_view_action_entries,
1139 G_N_ELEMENTS (modest_header_view_action_entries),
1142 gtk_action_group_add_toggle_actions (action_group,
1143 modest_main_window_toggle_action_entries,
1144 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1147 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1148 g_object_unref (action_group);
1150 /* Load the UI definition */
1151 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1152 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1153 if (error != NULL) {
1154 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1155 g_error_free (error);
1159 /* Add common dimming rules */
1160 modest_dimming_rules_group_add_rules (menu_rules_group,
1161 modest_main_window_menu_dimming_entries,
1162 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1163 MODEST_WINDOW (self));
1164 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1165 modest_main_window_toolbar_dimming_entries,
1166 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1167 MODEST_WINDOW (self));
1169 /* Insert dimming rules group for this window */
1170 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1171 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1172 g_object_unref (menu_rules_group);
1173 g_object_unref (toolbar_rules_group);
1175 /* Add accelerators */
1176 gtk_window_add_accel_group (GTK_WINDOW (self),
1177 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1179 /* Menubar. Update the state of some toggles */
1180 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1181 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1182 gtk_widget_show (parent_priv->menubar);
1184 /* Get device name */
1185 modest_maemo_utils_get_device_name ();
1189 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1190 g_object_ref (priv->header_view);
1191 if (!priv->header_view)
1192 g_printerr ("modest: cannot instantiate header view\n");
1193 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1194 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1195 MODEST_CONF_HEADER_VIEW_KEY);
1197 /* Other style properties of header view */
1198 g_object_set (G_OBJECT (priv->header_view),
1199 "rules-hint", FALSE,
1201 /* gtk_widget_show (priv->header_view); */
1204 priv->empty_view = create_empty_view ();
1205 gtk_widget_show (priv->empty_view);
1206 g_object_ref (priv->empty_view);
1208 /* Create scrolled windows */
1209 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1210 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1212 GTK_POLICY_AUTOMATIC);
1213 /* gtk_widget_show (priv->contents_widget); */
1215 /* putting it all together... */
1216 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1217 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->contents_widget, TRUE, TRUE,0);
1218 gtk_widget_show (priv->main_vbox);
1220 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1222 app = hildon_program_get_instance ();
1223 hildon_program_add_window (app, HILDON_WINDOW (self));
1225 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1226 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1228 /* Connect to "show" action. We delay the creation of some
1229 elements until that moment */
1230 helper = g_slice_new0 (ShowHelper);
1231 helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1232 G_CALLBACK (modest_main_window_on_show),
1235 /* Set window icon */
1236 window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1238 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1239 g_object_unref (window_icon);
1242 /* Listen for changes in the screen, we don't want to show a
1243 led pattern when the display is on for example */
1244 osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1245 osso_display_event_cb,
1248 /* Dont't restore settings here,
1249 * because it requires a gtk_widget_show(),
1250 * and we don't want to do that until later,
1251 * so that the UI is not visible for non-menu D-Bus activation.
1254 return MODEST_WINDOW(self);
1258 modest_main_window_set_style (ModestMainWindow *self,
1259 ModestMainWindowStyle style)
1261 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1263 /* We only provide simple style */
1267 ModestMainWindowStyle
1268 modest_main_window_get_style (ModestMainWindow *self)
1270 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1272 return MODEST_MAIN_WINDOW_STYLE_SIMPLE;
1276 toolbar_resize (ModestMainWindow *self)
1278 ModestMainWindowPrivate *priv = NULL;
1279 ModestWindowPrivate *parent_priv = NULL;
1281 gint static_button_size;
1282 ModestWindowMgr *mgr;
1284 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1285 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1286 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1288 mgr = modest_runtime_get_window_mgr ();
1289 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1291 if (parent_priv->toolbar) {
1292 /* left size buttons */
1293 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1294 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1295 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1296 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1297 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1298 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1299 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1300 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1301 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1302 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1303 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1304 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1305 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1306 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1307 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1308 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1310 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1311 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1312 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1313 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1314 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1315 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1316 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1317 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1323 modest_main_window_show_toolbar (ModestWindow *self,
1324 gboolean show_toolbar)
1326 ModestMainWindowPrivate *priv = NULL;
1327 ModestWindowPrivate *parent_priv = NULL;
1328 GtkWidget *reply_button = NULL, *menu = NULL;
1329 GtkWidget *placeholder = NULL;
1332 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1333 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1334 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1336 /* Set optimized view status */
1337 priv->optimized_view = !show_toolbar;
1339 if (!parent_priv->toolbar) {
1340 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1342 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1344 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1345 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1346 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1347 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1348 toolbar_resize (MODEST_MAIN_WINDOW (self));
1350 /* Add ProgressBar (Transfer toolbar) */
1351 priv->progress_bar = modest_progress_bar_new ();
1352 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1353 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1354 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1355 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1356 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1358 /* Connect cancel 'clicked' signal to abort progress mode */
1359 g_signal_connect(priv->cancel_toolitem, "clicked",
1360 G_CALLBACK(cancel_progressbar),
1363 /* Add it to the observers list */
1364 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1367 hildon_window_add_toolbar (HILDON_WINDOW (self),
1368 GTK_TOOLBAR (parent_priv->toolbar));
1370 /* Set reply button tap and hold menu */
1371 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1372 "/ToolBar/ToolbarMessageReply");
1373 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1374 "/ToolbarReplyCSM");
1375 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1377 /* Set send & receive button tap and hold menu */
1378 update_menus (MODEST_MAIN_WINDOW (self));
1382 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1383 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1384 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1386 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1387 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1388 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1390 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1392 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1398 on_account_inserted (TnyAccountStore *accoust_store,
1399 TnyAccount *account,
1402 /* Transport accounts and local ones (MMC and the Local
1403 folders account do now cause menu changes */
1404 if (TNY_IS_STORE_ACCOUNT (account) &&
1405 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1407 update_menus (MODEST_MAIN_WINDOW (user_data));
1412 on_default_account_changed (ModestAccountMgr* mgr,
1415 update_menus (MODEST_MAIN_WINDOW (user_data));
1419 on_account_removed (TnyAccountStore *accoust_store,
1420 TnyAccount *account,
1423 /* Transport accounts and local ones (MMC and the Local
1424 folders account do now cause menu changes */
1425 if (TNY_IS_STORE_ACCOUNT (account) &&
1426 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1427 update_menus (MODEST_MAIN_WINDOW (user_data));
1431 on_account_changed (TnyAccountStore *account_store,
1432 TnyAccount *account,
1435 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1437 /* Transport accounts and local ones (MMC and the Local
1438 folders account do now cause menu changes */
1439 if (TNY_IS_STORE_ACCOUNT (account)) {
1440 /* Update the menus as well, name could change */
1441 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1442 update_menus (MODEST_MAIN_WINDOW (win));
1447 * This function manages the key events used to navigate between
1448 * header and folder views (when the window is in split view)
1451 * -------------------------------------------------
1452 * HeaderView GDK_Left Move focus to folder view
1453 * FolderView GDK_Right Move focus to header view
1455 * There is no need to scroll to selected row, the widgets will be the
1456 * responsibles of doing that (probably managing the focus-in event
1459 on_inner_widgets_key_pressed (GtkWidget *widget,
1463 ModestMainWindowPrivate *priv;
1465 if (event->type == GDK_KEY_RELEASE)
1468 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1470 /* Do nothing if we're in SIMPLE style */
1471 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1474 if (MODEST_IS_HEADER_VIEW (widget)) {
1475 if (event->keyval == GDK_Left)
1476 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1477 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1478 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1479 if (selected_headers > 1) {
1480 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1483 GtkTreePath * cursor_path;
1484 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1485 if (cursor_path == NULL) {
1486 GtkTreeSelection *selection;
1488 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1489 list = gtk_tree_selection_get_selected_rows (selection, NULL);
1492 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1493 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1498 } else if (MODEST_IS_FOLDER_VIEW (widget) && (event->keyval == GDK_Right || event->keyval == GDK_Left)) {
1499 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1500 GtkTreePath *selected_path = NULL;
1501 GtkTreePath *start_path = NULL;
1502 GtkTreePath *end_path = NULL;
1504 GtkTreeSelection *selection;
1506 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1507 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1508 if (selected != NULL) {
1509 selected_path = (GtkTreePath *) selected->data;
1510 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1514 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1515 (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1517 /* Scroll to first path */
1518 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1527 gtk_tree_path_free (start_path);
1529 gtk_tree_path_free (end_path);
1530 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1531 g_list_free (selected);
1533 #endif /* GTK_CHECK_VERSION */
1535 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1542 create_empty_view (void)
1544 GtkLabel *label = NULL;
1545 GtkWidget *align = NULL;
1547 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1548 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1549 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1550 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1552 return GTK_WIDGET(align);
1557 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1559 ModestMainWindowPrivate *priv = NULL;
1561 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1563 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1565 return priv->send_receive_in_progress;
1569 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1571 GtkAction *action = NULL;
1572 GtkWidget *widget = NULL;
1573 ModestMainWindowPrivate *priv = NULL;
1575 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1576 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1578 priv->send_receive_in_progress = TRUE;
1580 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1581 gtk_action_set_sensitive (action, FALSE);
1582 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1583 /* gtk_action_set_sensitive (action, FALSE); */
1584 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1585 gtk_widget_set_sensitive (widget, FALSE);
1589 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1591 GtkAction *action = NULL;
1592 GtkWidget *widget = NULL;
1593 ModestMainWindowPrivate *priv = NULL;
1595 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1596 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1598 priv->send_receive_in_progress = FALSE;
1600 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1601 gtk_action_set_sensitive (action, TRUE);
1602 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1603 /* gtk_action_set_sensitive (action, TRUE); */
1604 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1605 gtk_widget_set_sensitive (widget, TRUE);
1610 on_msg_count_changed (ModestHeaderView *header_view,
1612 TnyFolderChange *change,
1613 ModestMainWindow *main_window)
1615 gboolean refilter = FALSE;
1616 gboolean folder_empty = FALSE;
1617 gboolean all_marked_as_deleted = FALSE;
1618 ModestMainWindowPrivate *priv;
1620 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1621 g_return_if_fail (TNY_IS_FOLDER(folder));
1622 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1624 if (change != NULL) {
1625 TnyFolderChangeChanged changed;
1627 changed = tny_folder_change_get_changed (change);
1628 /* If something changes */
1629 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1630 folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
1632 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
1634 /* Play a sound (if configured) and make the LED blink */
1635 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1636 modest_platform_push_email_notification ();
1639 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
1642 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
1645 /* Check if all messages are marked to be deleted */
1646 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1647 folder_empty = folder_empty || all_marked_as_deleted;
1649 /* Set contents style of headers view */
1650 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY ||
1651 priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1653 modest_main_window_set_contents_style (main_window,
1654 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1655 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1657 modest_main_window_set_contents_style (main_window,
1658 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1663 modest_header_view_refilter (header_view);
1668 modest_main_window_set_contents_style (ModestMainWindow *self,
1669 ModestMainWindowContentsStyle style)
1671 ModestMainWindowPrivate *priv;
1673 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1675 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1677 /* We allow to set the same content style than the previously
1678 set if there are details, because it could happen when we're
1679 selecting different accounts consecutively */
1680 if ((priv->contents_style == style) &&
1681 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1684 /* Remove previous child. Delete it if it was an account
1686 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1688 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1689 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1692 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1695 priv->contents_style = style;
1697 switch (priv->contents_style) {
1698 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_FOLDERS:
1699 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->folder_view));
1700 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1702 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1704 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1705 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1706 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1708 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1709 gtk_widget_show (GTK_WIDGET (priv->header_view));
1711 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1712 g_message ("This view is not supported in Fremantle style");
1714 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1715 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1716 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1718 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1719 gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
1722 g_return_if_reached ();
1726 gtk_widget_show_all (priv->contents_widget);
1729 ModestMainWindowContentsStyle
1730 modest_main_window_get_contents_style (ModestMainWindow *self)
1732 ModestMainWindowPrivate *priv;
1734 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1736 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1737 return priv->contents_style;
1742 on_configuration_key_changed (ModestConf* conf,
1744 ModestConfEvent event,
1745 ModestConfNotificationId id,
1746 ModestMainWindow *self)
1748 /* TODO: remove this handler. Now we don't support details view,
1749 * so this must be removed */
1755 set_toolbar_transfer_mode (ModestMainWindow *self)
1757 ModestMainWindowPrivate *priv = NULL;
1759 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1761 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1763 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1765 if (priv->progress_bar_timeout > 0) {
1766 g_source_remove (priv->progress_bar_timeout);
1767 priv->progress_bar_timeout = 0;
1774 set_toolbar_mode (ModestMainWindow *self,
1775 ModestToolBarModes mode)
1777 ModestWindowPrivate *parent_priv = NULL;
1778 ModestMainWindowPrivate *priv = NULL;
1779 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1781 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1783 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1784 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1786 /* In case this was called before the toolbar exists: */
1787 if (!(parent_priv->toolbar))
1790 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1792 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1793 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1794 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1796 /* Sets current toolbar mode */
1797 priv->current_toolbar_mode = mode;
1799 /* Checks the dimming rules */
1800 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1801 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1803 /* Show and hide toolbar items */
1805 case TOOLBAR_MODE_NORMAL:
1807 gtk_action_set_visible (sort_action, TRUE);
1809 gtk_action_set_visible (refresh_action, TRUE);
1810 if (priv->progress_toolitem) {
1811 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1812 gtk_widget_hide (priv->progress_toolitem);
1814 if (priv->progress_bar)
1815 gtk_widget_hide (priv->progress_bar);
1818 gtk_action_set_visible (cancel_action, FALSE);
1820 /* Hide toolbar if optimized view is enabled */
1821 if (priv->optimized_view)
1822 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1824 case TOOLBAR_MODE_TRANSFER:
1826 gtk_action_set_visible (sort_action, FALSE);
1828 gtk_action_set_visible (refresh_action, FALSE);
1830 gtk_action_set_visible (cancel_action, TRUE);
1831 if (priv->progress_bar)
1832 gtk_widget_show (priv->progress_bar);
1833 if (priv->progress_toolitem) {
1834 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1835 gtk_widget_show (priv->progress_toolitem);
1838 /* Show toolbar if it's hiden (optimized view ) */
1839 if (priv->optimized_view)
1840 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1843 g_return_if_reached ();
1848 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
1850 ModestMainWindowPrivate *priv;
1852 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1853 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1855 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1859 cancel_progressbar (GtkToolButton *toolbutton,
1860 ModestMainWindow *self)
1863 ModestMainWindowPrivate *priv;
1865 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1867 /* Get operation observers and cancel all the operations */
1868 tmp = priv->progress_widgets;
1870 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1871 tmp=g_slist_next(tmp);
1876 observers_empty (ModestMainWindow *self)
1879 ModestMainWindowPrivate *priv;
1880 gboolean is_empty = TRUE;
1881 guint pending_ops = 0;
1883 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1884 tmp = priv->progress_widgets;
1886 /* Check all observers */
1887 while (tmp && is_empty) {
1888 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1889 is_empty = pending_ops == 0;
1891 tmp = g_slist_next(tmp);
1899 * Gets the toolbar mode needed for each mail operation. It stores in
1900 * @mode_changed if the toolbar mode has changed or not
1902 static ModestToolBarModes
1903 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
1904 ModestMailOperation *mail_op,
1905 gboolean *mode_changed)
1907 ModestToolBarModes mode;
1908 ModestMainWindowPrivate *priv;
1910 *mode_changed = FALSE;
1911 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1913 /* Get toolbar mode from operation id*/
1914 switch (modest_mail_operation_get_type_operation (mail_op)) {
1915 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
1916 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1917 mode = TOOLBAR_MODE_TRANSFER;
1918 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1919 *mode_changed = TRUE;
1922 mode = TOOLBAR_MODE_NORMAL;
1928 on_mail_operation_started (ModestMailOperation *mail_op,
1931 ModestMainWindow *self;
1932 ModestMailOperationTypeOperation op_type;
1933 ModestMainWindowPrivate *priv;
1934 ModestToolBarModes mode;
1936 gboolean mode_changed = FALSE;
1937 TnyAccount *account = NULL;
1939 self = MODEST_MAIN_WINDOW (user_data);
1940 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1942 /* Do not show progress for receiving operations if the
1943 account is the local account or the MMC one */
1944 op_type = modest_mail_operation_get_type_operation (mail_op);
1945 account = modest_mail_operation_get_account (mail_op);
1946 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
1949 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
1950 modest_tny_account_is_memory_card_account (account));
1952 g_object_unref (account);
1956 /* Show information banner. Remove old timeout */
1957 if (priv->opening_banner_timeout > 0) {
1958 g_source_remove (priv->opening_banner_timeout);
1959 priv->opening_banner_timeout = 0;
1961 /* Create a new timeout */
1962 priv->opening_banner_timeout =
1963 g_timeout_add (2000, show_opening_banner, self);
1966 /* Not every mail operation has account, noop does not */
1968 g_object_unref (account);
1970 /* Get toolbar mode from operation id*/
1971 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
1973 /* Add operation observers and change toolbar if neccessary*/
1974 tmp = priv->progress_widgets;
1975 if (mode == TOOLBAR_MODE_TRANSFER) {
1977 GObject *source = modest_mail_operation_get_source(mail_op);
1978 if (G_OBJECT (self) == source) {
1979 set_toolbar_transfer_mode(self);
1981 g_object_unref (source);
1985 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1987 tmp = g_slist_next (tmp);
1991 /* Update the main menu as well, we need to explicitely do
1992 this in order to enable/disable accelerators */
1993 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1997 on_mail_operation_finished (ModestMailOperation *mail_op,
2000 ModestToolBarModes mode;
2001 ModestMailOperationTypeOperation op_type;
2003 ModestMainWindow *self;
2004 gboolean mode_changed;
2005 TnyAccount *account = NULL;
2006 ModestMainWindowPrivate *priv;
2008 self = MODEST_MAIN_WINDOW (user_data);
2009 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2011 /* The mail operation was not added to the progress objects if
2012 the account was the local account or the MMC one */
2013 op_type = modest_mail_operation_get_type_operation (mail_op);
2014 account = modest_mail_operation_get_account (mail_op);
2015 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2018 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2019 modest_tny_account_is_memory_card_account (account));
2021 g_object_unref (account);
2025 /* Remove old timeout */
2026 if (priv->opening_banner_timeout > 0) {
2027 g_source_remove (priv->opening_banner_timeout);
2028 priv->opening_banner_timeout = 0;
2031 /* Remove the banner if exists */
2032 if (priv->opening_banner) {
2033 gtk_widget_destroy (priv->opening_banner);
2034 priv->opening_banner = NULL;
2038 /* Not every mail operation has account, noop does not */
2040 g_object_unref (account);
2042 /* Get toolbar mode from operation id*/
2043 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2045 /* Change toolbar mode */
2046 tmp = priv->progress_widgets;
2047 if (mode == TOOLBAR_MODE_TRANSFER) {
2049 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2051 tmp = g_slist_next (tmp);
2054 /* If no more operations are being observed, NORMAL mode is enabled again */
2055 if (observers_empty (self)) {
2056 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2062 on_queue_changed (ModestMailOperationQueue *queue,
2063 ModestMailOperation *mail_op,
2064 ModestMailOperationQueueNotification type,
2065 ModestMainWindow *self)
2067 ModestMainWindowPrivate *priv;
2069 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2071 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2072 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2074 "operation-started",
2075 G_CALLBACK (on_mail_operation_started),
2077 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2079 "operation-finished",
2080 G_CALLBACK (on_mail_operation_finished),
2082 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2083 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2085 "operation-started");
2086 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2088 "operation-finished");
2093 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2095 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2097 ModestAccountMgr *mgr;
2098 ModestAccountSettings *settings;
2099 ModestServerAccountSettings *store_settings = NULL;
2101 /* Get account data */
2102 mgr = modest_runtime_get_account_mgr ();
2103 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2105 store_settings = modest_account_settings_get_store_settings (settings);
2107 /* Set the new visible & active account */
2108 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2109 const gchar *account_name;
2111 account_name = modest_account_settings_get_account_name (settings);
2113 modest_folder_view_set_account_id_of_visible_server_account
2115 modest_server_account_settings_get_account_name (store_settings));
2116 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2117 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2119 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2120 if (action != NULL) {
2121 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2122 modest_utils_toggle_action_set_active_block_notify (
2123 GTK_TOGGLE_ACTION (action),
2131 g_object_unref (store_settings);
2132 g_object_unref (settings);
2136 /* Make sure that at least one account is "viewed": */
2138 set_at_least_one_account_visible(ModestMainWindow *self)
2140 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2141 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2143 if (!(priv->folder_view)) {
2144 /* It is too early to do this. */
2148 const gchar *active_server_account_name =
2149 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2151 if (!active_server_account_name ||
2152 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2154 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2155 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2156 if (default_modest_name) {
2157 set_account_visible (self, default_modest_name);
2158 } else if (first_modest_name) {
2159 set_account_visible (self, first_modest_name);
2161 g_free (first_modest_name);
2162 g_free (default_modest_name);
2167 on_show_account_action_toggled (GtkToggleAction *action,
2170 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2172 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2173 if (gtk_toggle_action_get_active (action))
2174 set_account_visible (self, acc_name);
2178 refresh_account (const gchar *account_name)
2182 /* win must already exists here, obviously */
2183 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2186 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2190 /* If account_name == NULL, we must update all (option All) */
2192 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2194 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2199 on_refresh_account_action_activated (GtkAction *action,
2202 refresh_account ((const gchar*) user_data);
2206 on_send_receive_csm_activated (GtkMenuItem *item,
2209 refresh_account ((const gchar*) user_data);
2213 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2215 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2217 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2223 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2225 ModestMainWindow *main_window = NULL;
2227 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2228 main_window = MODEST_MAIN_WINDOW (userdata);
2230 /* Update toolbar dimming state */
2231 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2232 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2238 on_header_view_focus_in (GtkWidget *widget,
2239 GdkEventFocus *event,
2242 ModestMainWindow *main_window = NULL;
2244 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2246 main_window = MODEST_MAIN_WINDOW (userdata);
2248 /* Update toolbar dimming state */
2249 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2250 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2256 on_folder_selection_changed (ModestFolderView *folder_view,
2257 TnyFolderStore *folder_store,
2259 ModestMainWindow *main_window)
2261 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2262 GtkAction *action = NULL;
2263 gboolean show_reply = TRUE;
2264 gboolean show_forward = TRUE;
2265 gboolean show_cancel_send = FALSE;
2266 gboolean show_clipboard = TRUE;
2267 gboolean show_delete = TRUE;
2270 if (TNY_IS_ACCOUNT (folder_store)) {
2271 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2272 } else if (TNY_IS_FOLDER (folder_store)) {
2273 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2274 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2275 TNY_FOLDER (folder_store));
2276 switch (folder_type) {
2277 case TNY_FOLDER_TYPE_DRAFTS:
2278 show_clipboard = show_delete = TRUE;
2279 show_reply = show_forward = show_cancel_send = FALSE;
2281 case TNY_FOLDER_TYPE_SENT:
2282 show_forward = show_clipboard = show_delete = TRUE;
2283 show_reply = show_cancel_send = FALSE;
2285 case TNY_FOLDER_TYPE_OUTBOX:
2286 show_clipboard = show_delete = show_cancel_send = TRUE;
2287 show_reply = show_forward = FALSE;
2289 case TNY_FOLDER_TYPE_INVALID:
2290 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2293 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2294 show_cancel_send = FALSE;
2297 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2298 show_cancel_send = FALSE;
2303 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2304 gtk_action_set_visible (action, show_reply);
2305 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2306 gtk_action_set_visible (action, show_reply);
2307 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2308 gtk_action_set_visible (action, show_forward);
2309 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2310 gtk_action_set_visible (action, show_cancel_send);
2311 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2312 gtk_action_set_visible (action, show_delete);
2317 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2318 GtkTreeModel *model,
2319 GtkTreeRowReference *row_reference,
2320 ModestMainWindow *self)
2322 ModestMainWindowPrivate *priv = NULL;
2323 GtkTreeModel *header_model = NULL;
2324 GtkTreePath *path = NULL;
2326 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2327 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2328 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2330 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2331 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2333 /* Do nothing if we changed the folder in the main view */
2334 if (header_model != model)
2337 /* Select the message in the header view */
2338 path = gtk_tree_row_reference_get_path (row_reference);
2339 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2341 gtk_tree_path_free (path);
2347 updating_banner_destroyed (gpointer data,
2348 GObject *where_the_object_was)
2350 ModestMainWindowPrivate *priv = NULL;
2352 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2354 priv->updating_banner = NULL;
2358 show_updating_banner (gpointer user_data)
2360 ModestMainWindowPrivate *priv = NULL;
2362 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2364 if (priv->updating_banner == NULL) {
2366 /* We're outside the main lock */
2367 gdk_threads_enter ();
2368 priv->updating_banner =
2369 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2370 _CS ("ckdg_pb_updating"));
2372 /* We need this because banners in Maemo could be
2373 destroyed by dialogs so we need to properly update
2374 our reference to it */
2375 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2376 updating_banner_destroyed,
2378 gdk_threads_leave ();
2381 /* Remove timeout */
2382 priv->updating_banner_timeout = 0;
2387 * We use this function to show/hide a progress banner showing
2388 * "Updating" while the header view is being filled. We're not showing
2389 * it unless the update takes more than 2 seconds
2391 * If starting = TRUE then the refresh is starting, otherwise it means
2392 * that is has just finished
2395 on_updating_msg_list (ModestHeaderView *header_view,
2399 ModestMainWindowPrivate *priv = NULL;
2401 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2403 /* Remove old timeout */
2404 if (priv->updating_banner_timeout > 0) {
2405 g_source_remove (priv->updating_banner_timeout);
2406 priv->updating_banner_timeout = 0;
2409 /* Create a new timeout */
2411 priv->updating_banner_timeout =
2412 g_timeout_add (2000, show_updating_banner, user_data);
2414 /* Remove the banner if exists */
2415 if (priv->updating_banner) {
2416 gtk_widget_destroy (priv->updating_banner);
2417 priv->updating_banner = NULL;
2422 static void on_folder_view_row_activated (GtkTreeView *tree_view,
2423 GtkTreePath *tree_path,
2424 GtkTreeViewColumn *column,
2427 GtkTreeModel *model;
2429 TnyFolderStore *folder_store = NULL;
2430 ModestMainWindow *self = (ModestMainWindow *) userdata;
2431 ModestMainWindowPrivate *priv = NULL;
2433 g_return_if_fail (MODEST_IS_MAIN_WINDOW(self));
2434 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2436 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
2438 if (gtk_tree_model_get_iter (model, &iter, tree_path)) {
2439 gtk_tree_model_get (model, &iter,
2440 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder_store,
2442 if (folder_store && TNY_IS_FOLDER (folder_store)) {
2443 modest_header_view_set_folder (MODEST_HEADER_VIEW (priv->header_view),
2444 TNY_FOLDER (folder_store), TRUE,
2446 modest_main_window_set_contents_style (MODEST_MAIN_WINDOW (self),
2447 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2448 modest_widget_memory_restore (modest_runtime_get_conf (),
2449 G_OBJECT(priv->header_view),
2450 MODEST_CONF_HEADER_VIEW_KEY);
2451 on_msg_count_changed (MODEST_HEADER_VIEW (priv->header_view), TNY_FOLDER (folder_store), NULL, self);
2455 g_object_unref (folder_store);
2458 g_message ("FOLDER VIEW CELL ACTIVATED");
2463 modest_main_window_screen_is_on (ModestMainWindow *self)
2465 ModestMainWindowPrivate *priv = NULL;
2467 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2469 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2471 return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2475 remove_banners (ModestMainWindow *window)
2477 ModestMainWindowPrivate *priv;
2479 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2481 if (priv->opening_banner_timeout > 0) {
2482 g_source_remove (priv->opening_banner_timeout);
2483 priv->opening_banner_timeout = 0;
2486 if (priv->opening_banner != NULL) {
2487 gtk_widget_destroy (priv->opening_banner);
2488 priv->opening_banner = NULL;
2491 if (priv->updating_banner_timeout > 0) {
2492 g_source_remove (priv->updating_banner_timeout);
2493 priv->updating_banner_timeout = 0;
2496 if (priv->updating_banner != NULL) {
2497 gtk_widget_destroy (priv->updating_banner);
2498 priv->updating_banner = NULL;
2504 on_window_hide (GObject *gobject,
2508 g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
2510 if (!GTK_WIDGET_VISIBLE (gobject)) {
2511 TnyFolderStore *folder_store;
2512 ModestMainWindowPrivate *priv;
2514 /* Remove the currently shown banners */
2515 remove_banners (MODEST_MAIN_WINDOW (gobject));
2517 /* Force the folder view to sync the currently selected folder
2518 to save the read/unread status and to expunge messages */
2519 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
2520 folder_store = modest_folder_view_get_selected (priv->folder_view);
2521 if (TNY_IS_FOLDER (folder_store)) {
2522 ModestMailOperation *mail_op;
2524 mail_op = modest_mail_operation_new (NULL);
2525 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2527 modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
2528 g_object_unref (mail_op);
2529 g_object_unref (folder_store);
2535 on_window_destroy (GtkObject *widget,
2538 g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
2540 remove_banners (MODEST_MAIN_WINDOW (widget));
2544 opening_banner_destroyed (gpointer data,
2545 GObject *where_the_object_was)
2547 ModestMainWindowPrivate *priv = NULL;
2549 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2551 priv->opening_banner = NULL;
2555 show_opening_banner (gpointer user_data)
2557 ModestMainWindowPrivate *priv = NULL;
2559 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2561 if (priv->opening_banner == NULL) {
2563 /* We're outside the main lock */
2564 gdk_threads_enter ();
2565 priv->opening_banner =
2566 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2567 _("mail_me_opening"));
2569 /* We need this because banners in Maemo could be
2570 destroyed by dialogs so we need to properly update
2571 our reference to it */
2572 g_object_weak_ref (G_OBJECT (priv->opening_banner),
2573 opening_banner_destroyed,
2576 /* We need this because banners in Maemo could be
2577 destroyed by dialogs so we need to properly update
2578 our reference to it */
2579 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2580 updating_banner_destroyed,
2582 gdk_threads_leave ();
2585 /* Remove timeout */
2586 priv->opening_banner_timeout = 0;