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>
68 #include <modest-folder-window.h>
70 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
77 /* 'private'/'protected' functions */
78 static void modest_main_window_class_init (ModestMainWindowClass *klass);
79 static void modest_main_window_init (ModestMainWindow *obj);
80 static void modest_main_window_finalize (GObject *obj);
82 static void connect_signals (ModestMainWindow *self);
84 static void modest_main_window_disconnect_signals (ModestWindow *self);
86 static void restore_settings (ModestMainWindow *self,
87 gboolean do_folder_view_too);
89 static void save_state (ModestWindow *self);
91 static void update_menus (ModestMainWindow* self);
93 static void modest_main_window_show_toolbar (ModestWindow *window,
94 gboolean show_toolbar);
96 static void cancel_progressbar (GtkToolButton *toolbutton,
97 ModestMainWindow *self);
99 static void on_queue_changed (ModestMailOperationQueue *queue,
100 ModestMailOperation *mail_op,
101 ModestMailOperationQueueNotification type,
102 ModestMainWindow *self);
104 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
106 static void on_account_inserted (TnyAccountStore *accoust_store,
110 static void on_account_removed (TnyAccountStore *accoust_store,
114 static void on_account_changed (TnyAccountStore *account_store,
118 static void on_default_account_changed (ModestAccountMgr* mgr,
121 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
125 static void on_configuration_key_changed (ModestConf* conf,
127 ModestConfEvent event,
128 ModestConfNotificationId id,
129 ModestMainWindow *self);
131 static void set_toolbar_mode (ModestMainWindow *self,
132 ModestToolBarModes mode);
134 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
136 static void on_show_account_action_toggled (GtkToggleAction *action,
139 static void on_refresh_account_action_activated (GtkAction *action,
142 static void on_send_receive_csm_activated (GtkMenuItem *item,
145 static void on_folder_view_row_activated (GtkTreeView *tree_view,
146 GtkTreePath *tree_path,
147 GtkTreeViewColumn *column,
149 static void on_msg_count_changed (ModestHeaderView *header_view,
151 TnyFolderChange *change,
152 ModestMainWindow *main_window);
154 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
157 static GtkWidget * create_empty_view (void);
159 static gboolean on_folder_view_focus_in (GtkWidget *widget,
160 GdkEventFocus *event,
163 static gboolean on_header_view_focus_in (GtkWidget *widget,
164 GdkEventFocus *event,
167 static void on_folder_selection_changed (ModestFolderView *folder_view,
168 TnyFolderStore *folder_store,
170 ModestMainWindow *main_window);
172 static void set_at_least_one_account_visible(ModestMainWindow *self);
174 static void on_updating_msg_list (ModestHeaderView *header_view,
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 *main_vbox;
190 GtkWidget *contents_widget;
191 GtkWidget *empty_view;
193 /* Progress observers */
194 GtkWidget *progress_bar;
195 GSList *progress_widgets;
198 GtkWidget *progress_toolitem;
199 GtkWidget *cancel_toolitem;
200 GtkWidget *sort_toolitem;
201 GtkWidget *refresh_toolitem;
202 ModestToolBarModes current_toolbar_mode;
204 /* Merge ids used to add/remove accounts to the Accounts Menu*/
205 GByteArray *merge_ids;
206 GtkActionGroup *view_additions_group;
208 /* On-demand widgets */
209 GtkWidget *accounts_popup;
210 GtkWidget *details_widget;
212 /* Optimized view enabled */
213 gboolean optimized_view;
215 /* Optimized view enabled */
216 gboolean send_receive_in_progress;
218 ModestHeaderView *header_view;
219 ModestFolderView *folder_view;
221 ModestMainWindowStyle style;
222 ModestMainWindowContentsStyle contents_style;
223 gboolean wait_for_settings;
225 guint progress_bar_timeout;
227 /* Signal handler UIDs */
228 GList *queue_err_signals;
231 /* "Updating" banner for header view */
232 GtkWidget *updating_banner;
233 guint updating_banner_timeout;
235 /* "Opening" banner for header view */
236 GtkWidget *opening_banner;
237 guint opening_banner_timeout;
240 osso_display_state_t display_state;
242 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
243 MODEST_TYPE_MAIN_WINDOW, \
244 ModestMainWindowPrivate))
246 typedef struct _GetMsgAsyncHelper {
247 ModestMainWindowPrivate *main_window_private;
249 ModestTnyMsgReplyType reply_type;
250 ModestTnyMsgForwardType forward_type;
257 static GtkWindowClass *parent_class = NULL;
260 /* Private actions */
261 /* This is the context sensitive menu: */
262 static const GtkActionEntry modest_folder_view_action_entries [] = {
264 /* Folder View CSM actions */
265 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
266 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
267 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
268 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
271 static const GtkActionEntry modest_header_view_action_entries [] = {
273 /* Header View CSM actions */
274 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
275 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
276 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
277 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
278 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
279 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
280 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
281 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
282 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
285 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
286 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
289 /************************************************************************/
292 modest_main_window_get_type (void)
294 static GType my_type = 0;
296 static const GTypeInfo my_info = {
297 sizeof(ModestMainWindowClass),
298 NULL, /* base init */
299 NULL, /* base finalize */
300 (GClassInitFunc) modest_main_window_class_init,
301 NULL, /* class finalize */
302 NULL, /* class data */
303 sizeof(ModestMainWindow),
305 (GInstanceInitFunc) modest_main_window_init,
308 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
316 modest_main_window_class_init (ModestMainWindowClass *klass)
318 GObjectClass *gobject_class;
319 gobject_class = (GObjectClass*) klass;
320 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
322 parent_class = g_type_class_peek_parent (klass);
323 gobject_class->finalize = modest_main_window_finalize;
325 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
327 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
328 modest_window_class->save_state_func = save_state;
329 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
330 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
331 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
335 modest_main_window_init (ModestMainWindow *obj)
337 ModestMainWindowPrivate *priv;
339 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
341 priv->queue_err_signals = NULL;
342 priv->main_vbox = NULL;
343 priv->header_view = NULL;
344 priv->folder_view = NULL;
345 priv->contents_widget = NULL;
346 priv->accounts_popup = NULL;
347 priv->details_widget = NULL;
348 priv->empty_view = NULL;
349 priv->progress_widgets = NULL;
350 priv->progress_bar = NULL;
351 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
352 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
353 priv->wait_for_settings = TRUE;
354 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
355 priv->merge_ids = NULL;
356 priv->optimized_view = FALSE;
357 priv->send_receive_in_progress = FALSE;
358 priv->progress_bar_timeout = 0;
359 priv->sighandlers = NULL;
360 priv->updating_banner = NULL;
361 priv->updating_banner_timeout = 0;
362 priv->opening_banner = NULL;
363 priv->opening_banner_timeout = 0;
364 priv->display_state = OSSO_DISPLAY_ON;
366 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
368 "applications_email_mainview");
372 modest_main_window_finalize (GObject *obj)
374 ModestMainWindowPrivate *priv;
376 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
378 /* Sanity check: shouldn't be needed, the window mgr should
379 call this function before */
380 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
381 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
383 if (priv->empty_view) {
384 g_object_unref (priv->empty_view);
385 priv->empty_view = NULL;
388 if (priv->header_view) {
389 g_object_unref (priv->header_view);
390 priv->header_view = NULL;
393 g_slist_free (priv->progress_widgets);
395 g_byte_array_free (priv->merge_ids, TRUE);
397 if (priv->progress_bar_timeout > 0) {
398 g_source_remove (priv->progress_bar_timeout);
399 priv->progress_bar_timeout = 0;
402 if (priv->updating_banner_timeout > 0) {
403 g_source_remove (priv->updating_banner_timeout);
404 priv->updating_banner_timeout = 0;
407 if (priv->updating_banner) {
408 gtk_widget_destroy (priv->updating_banner);
409 priv->updating_banner = NULL;
412 if (priv->opening_banner_timeout > 0) {
413 g_source_remove (priv->opening_banner_timeout);
414 priv->opening_banner_timeout = 0;
417 if (priv->opening_banner) {
418 gtk_widget_destroy (priv->opening_banner);
419 priv->opening_banner = NULL;
422 G_OBJECT_CLASS(parent_class)->finalize (obj);
426 modest_main_window_get_child_widget (ModestMainWindow *self,
427 ModestMainWindowWidgetType widget_type)
429 ModestMainWindowPrivate *priv;
432 g_return_val_if_fail (self && MODEST_IS_MAIN_WINDOW(self), NULL);
433 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
436 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
438 switch (widget_type) {
439 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
440 widget = (GtkWidget*)priv->header_view; break;
441 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
442 widget = (GtkWidget*)priv->folder_view; break;
447 /* Note that the window could have been destroyed, and so
448 their children, but still have some references */
449 return (widget && GTK_IS_WIDGET(widget)) ? GTK_WIDGET(widget) : NULL;
454 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
457 ModestMainWindowPrivate *priv;
459 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
461 conf = modest_runtime_get_conf ();
463 modest_widget_memory_restore (conf, G_OBJECT(self),
464 MODEST_CONF_MAIN_WINDOW_KEY);
466 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
467 MODEST_CONF_HEADER_VIEW_KEY);
469 if (do_folder_view_too)
470 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
471 MODEST_CONF_FOLDER_VIEW_KEY);
473 gtk_widget_show (GTK_WIDGET (self));
478 save_state (ModestWindow *window)
481 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
482 ModestMainWindowPrivate *priv;
484 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
485 conf = modest_runtime_get_conf ();
487 modest_widget_memory_save (conf,G_OBJECT(self),
488 MODEST_CONF_MAIN_WINDOW_KEY);
489 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
490 MODEST_CONF_FOLDER_VIEW_KEY);
494 compare_display_names (ModestAccountSettings *a,
495 ModestAccountSettings *b)
497 return g_utf8_collate (modest_account_settings_get_display_name (a),
498 modest_account_settings_get_display_name (b));
502 /* We use this function to prevent the send&receive CSM to be shown
503 when there are less than two account */
505 tap_and_hold_query_cb (GtkWidget *widget, GdkEvent *event)
511 update_menus (ModestMainWindow* self)
513 GSList *account_names, *iter, *accounts;
514 ModestMainWindowPrivate *priv;
515 ModestWindowPrivate *parent_priv;
516 ModestAccountMgr *mgr;
517 gint i, num_accounts;
519 gchar *default_account;
520 const gchar *active_account_name;
521 GtkWidget *send_receive_button, *item;
522 GtkAction *send_receive_all = NULL;
525 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
526 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
528 /* Get enabled account IDs */
529 mgr = modest_runtime_get_account_mgr ();
530 account_names = modest_account_mgr_account_names (mgr, TRUE);
531 iter = account_names;
535 ModestAccountSettings *settings =
536 modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
537 accounts = g_slist_prepend (accounts, settings);
541 modest_account_mgr_free_account_names (account_names);
542 account_names = NULL;
544 /* Order the list of accounts by its display name */
545 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
546 num_accounts = g_slist_length (accounts);
548 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
549 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
550 gtk_action_set_visible (send_receive_all, num_accounts > 0);
552 /* Delete old send&receive popup items. We can not just do a
553 menu_detach because it does not work well with
555 if (priv->accounts_popup)
556 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
557 (GtkCallback) gtk_widget_destroy, NULL);
559 /* Delete old entries in the View menu. Do not free groups, it
561 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
563 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
564 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
565 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
566 GTK_ACTION_GROUP (groups->data));
569 if (priv->merge_ids) {
570 for (i = 0; i < priv->merge_ids->len; i++)
571 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
572 g_byte_array_free (priv->merge_ids, TRUE);
574 /* We need to call this in order to ensure
575 that the new actions are added in the right
576 order (alphabetical) */
577 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
579 groups = g_list_next (groups);
581 priv->merge_ids = g_byte_array_sized_new (num_accounts);
583 /* Get send receive button */
584 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
585 "/ToolBar/ToolbarSendReceive");
587 /* Create the menu */
588 if (num_accounts > 1) {
589 if (!priv->accounts_popup)
590 priv->accounts_popup = gtk_menu_new ();
591 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
592 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
593 g_signal_connect (G_OBJECT (item),
595 G_CALLBACK (on_send_receive_csm_activated),
597 item = gtk_separator_menu_item_new ();
598 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
601 /* Create a new action group */
602 default_account = modest_account_mgr_get_default_account (mgr);
603 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
605 if (!active_account_name)
606 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
608 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
610 for (i = 0; i < num_accounts; i++) {
611 gchar *display_name = NULL;
612 const gchar *account_name;
613 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
616 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
619 account_name = modest_account_settings_get_account_name (settings);
621 if (default_account && account_name &&
622 !(strcmp (default_account, account_name) == 0)) {
623 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
624 modest_account_settings_get_display_name (settings));
626 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
627 modest_account_settings_get_display_name (settings));
632 /* Create action and add it to the action group. The
633 action name must be the account name, this way we
634 could know in the handlers the account to show */
635 if (settings && account_name) {
636 gchar* item_name, *refresh_action_name;
638 GtkAction *view_account_action, *refresh_account_action;
639 gchar *escaped_display_name;
641 escaped_display_name = modest_text_utils_escape_mnemonics (display_name);
643 view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
644 escaped_display_name, NULL, NULL, 0));
645 g_free (escaped_display_name);
646 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
647 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
648 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
650 if (active_account_name) {
651 if (active_account_name && account_name &&
652 (strcmp (active_account_name, account_name) == 0)) {
653 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
657 /* Add ui from account data. We allow 2^9-1 account
658 changes in a single execution because we're
659 downcasting the guint to a guint8 in order to use a
660 GByteArray. It should be enough :-) */
661 item_name = g_strconcat (account_name, "Menu", NULL);
662 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
663 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
664 gtk_ui_manager_add_ui (parent_priv->ui_manager,
666 "/MenuBar/AccountsMenu/AccountsMenuAdditions",
669 GTK_UI_MANAGER_MENUITEM,
672 /* Connect the action signal "activate" */
673 g_signal_connect_after (G_OBJECT (view_account_action),
675 G_CALLBACK (on_show_account_action_toggled),
678 /* Create the items for the Tools->Send&Receive submenu */
679 refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
680 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
681 display_name, NULL, NULL);
682 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
684 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
685 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
686 gtk_ui_manager_add_ui (parent_priv->ui_manager,
688 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
691 GTK_UI_MANAGER_MENUITEM,
693 g_free (refresh_action_name);
695 g_signal_connect_data (G_OBJECT (refresh_account_action),
697 G_CALLBACK (on_refresh_account_action_activated),
698 g_strdup (account_name),
699 (GClosureNotify) g_free,
702 /* Create item and add it to the send&receive
703 CSM. If there is only one account then
705 if (num_accounts > 1) {
706 GtkWidget *label = gtk_label_new(NULL);
707 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
708 if (default_account && (strcmp(account_name, default_account) == 0)) {
709 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
710 gtk_label_set_markup (GTK_LABEL (label), escaped);
713 gtk_label_set_text (GTK_LABEL (label), display_name);
716 item = gtk_menu_item_new ();
717 gtk_container_add (GTK_CONTAINER (item), label);
719 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup),
721 g_signal_connect_data (G_OBJECT (item),
723 G_CALLBACK (on_send_receive_csm_activated),
724 g_strdup (account_name),
725 (GClosureNotify) g_free,
732 g_free (display_name);
735 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
737 /* We cannot do this in the loop above because this relies on the action
738 * group being inserted. This makes the default account appear in bold.
739 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
740 for (i = 0; i < num_accounts; i++) {
741 gchar *item_name, *path;
743 ModestAccountSettings *settings;
744 const gchar *account_name;
747 settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
748 account_name = modest_account_settings_get_account_name (settings);
749 is_default = (account_name && default_account && !strcmp (account_name, default_account));
751 /* Get the item of the view menu */
752 item_name = g_strconcat (account_name, "Menu", NULL);
753 path = g_strconcat ("/MenuBar/AccountsMenu/AccountsMenuAdditions/", item_name, NULL);
754 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
758 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
759 if (GTK_IS_LABEL (child)) {
760 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
762 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
763 gtk_label_set_markup (GTK_LABEL (child), bold_name);
769 /* Get the item of the tools menu */
770 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
771 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
775 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
776 if (GTK_IS_LABEL (child)) {
777 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
779 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
780 gtk_label_set_markup (GTK_LABEL (child), bold_name);
783 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
788 g_object_unref (settings);
791 if (num_accounts > 1) {
792 /* Disconnect the tap-and-hold-query if it's connected */
793 if (modest_signal_mgr_is_connected (priv->sighandlers,
794 G_OBJECT (send_receive_button),
795 "tap-and-hold-query"))
796 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
797 G_OBJECT (send_receive_button),
798 "tap-and-hold-query");
800 /* Mandatory in order to view the menu contents */
801 gtk_widget_show_all (priv->accounts_popup);
803 /* Setup tap_and_hold just if was not done before*/
804 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
805 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
807 /* Connect the tap-and-hold-query in order not to show the CSM */
808 if (!modest_signal_mgr_is_connected (priv->sighandlers,
809 G_OBJECT (send_receive_button),
810 "tap-and-hold-query"))
811 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
812 G_OBJECT (send_receive_button),
813 "tap-and-hold-query",
814 G_CALLBACK (tap_and_hold_query_cb),
819 g_slist_free (accounts);
820 g_free (default_account);
823 /* Make sure that at least one account is viewed if there are any
824 * accounts, for instance when adding the first account: */
825 set_at_least_one_account_visible (self);
829 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
831 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
832 gtk_scrolled_window_add_with_viewport
833 (GTK_SCROLLED_WINDOW(win), widget);
835 gtk_container_add (GTK_CONTAINER(win),
846 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
848 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
850 GList *oerrsignals = priv->queue_err_signals;
851 while (oerrsignals) {
852 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
853 g_signal_handler_disconnect (esignal->queue, esignal->signal);
854 g_slice_free (QueueErrorSignal, esignal);
855 oerrsignals = g_list_next (oerrsignals);
857 g_list_free (priv->queue_err_signals);
858 priv->queue_err_signals = NULL;
863 modest_main_window_disconnect_signals (ModestWindow *self)
865 ModestMainWindowPrivate *priv;
866 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
868 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
869 priv->sighandlers = NULL;
873 connect_signals (ModestMainWindow *self)
875 ModestWindowPrivate *parent_priv;
876 ModestMainWindowPrivate *priv;
878 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
879 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
884 modest_signal_mgr_connect (priv->sighandlers,
885 G_OBJECT(priv->folder_view), "key-press-event",
886 G_CALLBACK(on_inner_widgets_key_pressed), self);
888 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
889 "folder_selection_changed",
890 G_CALLBACK (on_folder_selection_changed),
893 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
894 "folder-display-name-changed",
895 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
898 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
900 G_CALLBACK (on_folder_view_focus_in),
903 /* Folder view CSM */
904 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
905 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
906 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
907 G_CALLBACK(_folder_view_csm_menu_activated),
910 /* folder view row activated */
911 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "row-activated",
912 G_CALLBACK(on_folder_view_row_activated),
917 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
918 G_CALLBACK(modest_ui_actions_on_header_selected), self);
920 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
921 G_CALLBACK(modest_ui_actions_on_header_activated), self);
923 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
924 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
926 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
927 G_CALLBACK(on_inner_widgets_key_pressed), self);
929 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
930 G_CALLBACK(on_msg_count_changed), self);
932 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
933 G_CALLBACK (on_header_view_focus_in), self);
935 modest_signal_mgr_connect (priv->sighandlers,
936 G_OBJECT (priv->header_view),
938 G_CALLBACK (on_updating_msg_list),
942 /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
943 * in destroy stage */
944 g_signal_connect (G_OBJECT (self), "destroy", G_CALLBACK (on_window_destroy), NULL);
946 g_signal_connect (G_OBJECT (self), "notify::visible", G_CALLBACK (on_window_hide), NULL);
948 /* Mail Operation Queue */
950 modest_signal_mgr_connect (priv->sighandlers,
951 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
953 G_CALLBACK (on_queue_changed), self);
955 /* Track changes in the device name */
957 modest_signal_mgr_connect (priv->sighandlers,
958 G_OBJECT(modest_runtime_get_conf ()),
960 G_CALLBACK (on_configuration_key_changed),
963 /* Track account changes. We need to refresh the toolbar */
965 modest_signal_mgr_connect (priv->sighandlers,
966 G_OBJECT (modest_runtime_get_account_store ()),
968 G_CALLBACK (on_account_inserted),
971 modest_signal_mgr_connect (priv->sighandlers,
972 G_OBJECT (modest_runtime_get_account_store ()),
974 G_CALLBACK (on_account_removed),
977 /* We need to refresh the send & receive menu to change the bold
978 * account when the default account changes. */
980 modest_signal_mgr_connect (priv->sighandlers,
981 G_OBJECT (modest_runtime_get_account_mgr ()),
982 "default_account_changed",
983 G_CALLBACK (on_default_account_changed),
988 modest_signal_mgr_connect (priv->sighandlers,
989 G_OBJECT (modest_runtime_get_account_store ()),
991 G_CALLBACK (on_account_changed),
996 on_hildon_program_is_topmost_notify(GObject *self,
997 GParamSpec *propert_param,
1000 HildonProgram *app = HILDON_PROGRAM (self);
1002 /* Note that use of hildon_program_set_can_hibernate()
1003 * is generally referred to as "setting the killable flag",
1004 * though hibernation does not seem equal to death.
1007 if (hildon_program_get_is_topmost (app)) {
1008 /* Prevent hibernation when the progam comes to the foreground,
1009 * because hibernation should only happen when the application
1010 * is in the background: */
1011 hildon_program_set_can_hibernate (app, FALSE);
1013 /* Remove new mail visual notifications */
1014 modest_platform_remove_new_mail_notifications (TRUE);
1016 /* Allow hibernation if the program has gone to the background: */
1018 /* However, prevent hibernation while the settings are being changed: */
1019 const gboolean hibernation_prevented =
1020 modest_window_mgr_get_hibernation_is_prevented (
1021 modest_runtime_get_window_mgr ());
1023 if (hibernation_prevented)
1024 hildon_program_set_can_hibernate (app, FALSE);
1026 /* Allow hibernation, after saving the state: */
1027 modest_osso_save_state();
1028 hildon_program_set_can_hibernate (app, TRUE);
1039 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1041 ShowHelper *helper = (ShowHelper *) user_data;
1042 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1044 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1045 modest_main_window_set_contents_style (MODEST_MAIN_WINDOW (self),
1046 MODEST_MAIN_WINDOW_CONTENTS_STYLE_FOLDERS);
1047 gtk_tree_view_expand_all (GTK_TREE_VIEW (priv->folder_view));
1049 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1051 /* Connect signals */
1052 connect_signals (MODEST_MAIN_WINDOW (self));
1054 /* Set account store */
1055 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1056 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1058 /* Load previous osso state, for instance if we are being restored from
1060 modest_osso_load_state ();
1062 /* Restore window & widget settings */
1063 priv->wait_for_settings = TRUE;
1064 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1065 priv->wait_for_settings = FALSE;
1067 /* Check if accounts exist and show the account wizard if not */
1068 gboolean accounts_exist =
1069 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1071 if (!accounts_exist) {
1072 /* This is necessary to have the main window shown behind the dialog
1073 It's an ugly hack... jschmid */
1074 gtk_widget_show_all(GTK_WIDGET(self));
1075 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1077 update_menus (MODEST_MAIN_WINDOW (self));
1080 /* Never call this function again (NOTE that it could happen
1081 as we hide the main window instead of closing it while
1082 there are operations ongoing) and free the helper */
1083 g_signal_handler_disconnect (self, helper->handler_id);
1084 g_slice_free (ShowHelper, helper);
1088 osso_display_event_cb (osso_display_state_t state,
1091 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1093 priv->display_state = state;
1095 /* Stop blinking if the screen becomes on */
1096 if (priv->display_state == OSSO_DISPLAY_ON)
1097 modest_platform_remove_new_mail_notifications (TRUE);
1101 modest_main_window_new (void)
1103 ModestMainWindow *self = NULL;
1104 ModestMainWindowPrivate *priv = NULL;
1105 ModestWindowPrivate *parent_priv = NULL;
1106 ModestDimmingRulesGroup *menu_rules_group = NULL;
1107 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1108 GtkActionGroup *action_group = NULL;
1109 GError *error = NULL;
1111 GdkPixbuf *window_icon;
1114 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1115 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1116 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1118 parent_priv->ui_manager = gtk_ui_manager_new();
1119 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1121 action_group = gtk_action_group_new ("ModestMainWindowActions");
1122 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1124 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1125 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1127 /* Add common actions */
1128 gtk_action_group_add_actions (action_group,
1129 modest_action_entries,
1130 G_N_ELEMENTS (modest_action_entries),
1133 gtk_action_group_add_actions (action_group,
1134 modest_folder_view_action_entries,
1135 G_N_ELEMENTS (modest_folder_view_action_entries),
1138 gtk_action_group_add_actions (action_group,
1139 modest_header_view_action_entries,
1140 G_N_ELEMENTS (modest_header_view_action_entries),
1143 gtk_action_group_add_toggle_actions (action_group,
1144 modest_main_window_toggle_action_entries,
1145 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1148 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1149 g_object_unref (action_group);
1151 /* Load the UI definition */
1152 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1153 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1154 if (error != NULL) {
1155 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1156 g_error_free (error);
1160 /* Add common dimming rules */
1161 modest_dimming_rules_group_add_rules (menu_rules_group,
1162 modest_main_window_menu_dimming_entries,
1163 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1164 MODEST_WINDOW (self));
1165 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1166 modest_main_window_toolbar_dimming_entries,
1167 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1168 MODEST_WINDOW (self));
1170 /* Insert dimming rules group for this window */
1171 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1172 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1173 g_object_unref (menu_rules_group);
1174 g_object_unref (toolbar_rules_group);
1176 /* Add accelerators */
1177 gtk_window_add_accel_group (GTK_WINDOW (self),
1178 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1180 /* Menubar. Update the state of some toggles */
1181 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1182 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1183 gtk_widget_show (parent_priv->menubar);
1185 /* Get device name */
1186 modest_maemo_utils_get_device_name ();
1190 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1191 g_object_ref (priv->header_view);
1192 if (!priv->header_view)
1193 g_printerr ("modest: cannot instantiate header view\n");
1194 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1195 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1196 MODEST_CONF_HEADER_VIEW_KEY);
1198 /* Other style properties of header view */
1199 g_object_set (G_OBJECT (priv->header_view),
1200 "rules-hint", FALSE,
1202 /* gtk_widget_show (priv->header_view); */
1205 priv->empty_view = create_empty_view ();
1206 gtk_widget_show (priv->empty_view);
1207 g_object_ref (priv->empty_view);
1209 /* Create scrolled windows */
1210 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1211 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1213 GTK_POLICY_AUTOMATIC);
1214 /* gtk_widget_show (priv->contents_widget); */
1216 /* putting it all together... */
1217 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1218 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->contents_widget, TRUE, TRUE,0);
1219 gtk_widget_show (priv->main_vbox);
1221 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1223 app = hildon_program_get_instance ();
1224 hildon_program_add_window (app, HILDON_WINDOW (self));
1226 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1227 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1229 /* Connect to "show" action. We delay the creation of some
1230 elements until that moment */
1231 helper = g_slice_new0 (ShowHelper);
1232 helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1233 G_CALLBACK (modest_main_window_on_show),
1236 /* Set window icon */
1237 window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1239 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1240 g_object_unref (window_icon);
1243 /* Listen for changes in the screen, we don't want to show a
1244 led pattern when the display is on for example */
1245 osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1246 osso_display_event_cb,
1249 /* Dont't restore settings here,
1250 * because it requires a gtk_widget_show(),
1251 * and we don't want to do that until later,
1252 * so that the UI is not visible for non-menu D-Bus activation.
1255 return MODEST_WINDOW(self);
1259 modest_main_window_set_style (ModestMainWindow *self,
1260 ModestMainWindowStyle style)
1262 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1264 /* We only provide simple style */
1268 ModestMainWindowStyle
1269 modest_main_window_get_style (ModestMainWindow *self)
1271 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1273 return MODEST_MAIN_WINDOW_STYLE_SIMPLE;
1277 toolbar_resize (ModestMainWindow *self)
1279 ModestMainWindowPrivate *priv = NULL;
1280 ModestWindowPrivate *parent_priv = NULL;
1282 gint static_button_size;
1283 ModestWindowMgr *mgr;
1285 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1286 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1287 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1289 mgr = modest_runtime_get_window_mgr ();
1290 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1292 if (parent_priv->toolbar) {
1293 /* left size buttons */
1294 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1295 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1296 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1297 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1298 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1299 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1300 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1301 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1302 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1303 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1304 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1305 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1306 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1307 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1308 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1309 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1311 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1312 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1313 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1314 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1315 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1316 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1317 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1318 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1324 modest_main_window_show_toolbar (ModestWindow *self,
1325 gboolean show_toolbar)
1327 ModestMainWindowPrivate *priv = NULL;
1328 ModestWindowPrivate *parent_priv = NULL;
1329 GtkWidget *reply_button = NULL, *menu = NULL;
1330 GtkWidget *placeholder = NULL;
1333 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1334 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1335 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1337 /* Set optimized view status */
1338 priv->optimized_view = !show_toolbar;
1340 if (!parent_priv->toolbar) {
1341 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1343 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1345 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1346 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1347 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1348 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1349 toolbar_resize (MODEST_MAIN_WINDOW (self));
1351 /* Add ProgressBar (Transfer toolbar) */
1352 priv->progress_bar = modest_progress_bar_new ();
1353 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1354 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1355 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1356 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1357 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1359 /* Connect cancel 'clicked' signal to abort progress mode */
1360 g_signal_connect(priv->cancel_toolitem, "clicked",
1361 G_CALLBACK(cancel_progressbar),
1364 /* Add it to the observers list */
1365 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1368 hildon_window_add_toolbar (HILDON_WINDOW (self),
1369 GTK_TOOLBAR (parent_priv->toolbar));
1371 /* Set reply button tap and hold menu */
1372 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1373 "/ToolBar/ToolbarMessageReply");
1374 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1375 "/ToolbarReplyCSM");
1376 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1378 /* Set send & receive button tap and hold menu */
1379 update_menus (MODEST_MAIN_WINDOW (self));
1383 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1384 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1385 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1387 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1388 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1389 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1391 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1393 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1399 on_account_inserted (TnyAccountStore *accoust_store,
1400 TnyAccount *account,
1403 /* Transport accounts and local ones (MMC and the Local
1404 folders account do now cause menu changes */
1405 if (TNY_IS_STORE_ACCOUNT (account) &&
1406 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1408 update_menus (MODEST_MAIN_WINDOW (user_data));
1413 on_default_account_changed (ModestAccountMgr* mgr,
1416 update_menus (MODEST_MAIN_WINDOW (user_data));
1420 on_account_removed (TnyAccountStore *accoust_store,
1421 TnyAccount *account,
1424 /* Transport accounts and local ones (MMC and the Local
1425 folders account do now cause menu changes */
1426 if (TNY_IS_STORE_ACCOUNT (account) &&
1427 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1428 update_menus (MODEST_MAIN_WINDOW (user_data));
1432 on_account_changed (TnyAccountStore *account_store,
1433 TnyAccount *account,
1436 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1438 /* Transport accounts and local ones (MMC and the Local
1439 folders account do now cause menu changes */
1440 if (TNY_IS_STORE_ACCOUNT (account)) {
1441 /* Update the menus as well, name could change */
1442 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1443 update_menus (MODEST_MAIN_WINDOW (win));
1448 * This function manages the key events used to navigate between
1449 * header and folder views (when the window is in split view)
1452 * -------------------------------------------------
1453 * HeaderView GDK_Left Move focus to folder view
1454 * FolderView GDK_Right Move focus to header view
1456 * There is no need to scroll to selected row, the widgets will be the
1457 * responsibles of doing that (probably managing the focus-in event
1460 on_inner_widgets_key_pressed (GtkWidget *widget,
1464 ModestMainWindowPrivate *priv;
1466 if (event->type == GDK_KEY_RELEASE)
1469 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1471 /* Do nothing if we're in SIMPLE style */
1472 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1475 if (MODEST_IS_HEADER_VIEW (widget)) {
1476 if (event->keyval == GDK_Left)
1477 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1478 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1479 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1480 if (selected_headers > 1) {
1481 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1484 GtkTreePath * cursor_path;
1485 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1486 if (cursor_path == NULL) {
1487 GtkTreeSelection *selection;
1489 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1490 list = gtk_tree_selection_get_selected_rows (selection, NULL);
1493 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1494 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1499 } else if (MODEST_IS_FOLDER_VIEW (widget) && (event->keyval == GDK_Right || event->keyval == GDK_Left)) {
1500 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1501 GtkTreePath *selected_path = NULL;
1502 GtkTreePath *start_path = NULL;
1503 GtkTreePath *end_path = NULL;
1505 GtkTreeSelection *selection;
1507 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1508 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1509 if (selected != NULL) {
1510 selected_path = (GtkTreePath *) selected->data;
1511 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1515 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1516 (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1518 /* Scroll to first path */
1519 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1528 gtk_tree_path_free (start_path);
1530 gtk_tree_path_free (end_path);
1531 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1532 g_list_free (selected);
1534 #endif /* GTK_CHECK_VERSION */
1536 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1543 create_empty_view (void)
1545 GtkLabel *label = NULL;
1546 GtkWidget *align = NULL;
1548 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1549 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1550 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1551 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1553 return GTK_WIDGET(align);
1558 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1560 ModestMainWindowPrivate *priv = NULL;
1562 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1564 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1566 return priv->send_receive_in_progress;
1570 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1572 GtkAction *action = NULL;
1573 GtkWidget *widget = NULL;
1574 ModestMainWindowPrivate *priv = NULL;
1576 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1577 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1579 priv->send_receive_in_progress = TRUE;
1581 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1582 gtk_action_set_sensitive (action, FALSE);
1583 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1584 /* gtk_action_set_sensitive (action, FALSE); */
1585 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1586 gtk_widget_set_sensitive (widget, FALSE);
1590 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1592 GtkAction *action = NULL;
1593 GtkWidget *widget = NULL;
1594 ModestMainWindowPrivate *priv = NULL;
1596 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1597 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1599 priv->send_receive_in_progress = FALSE;
1601 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1602 gtk_action_set_sensitive (action, TRUE);
1603 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1604 /* gtk_action_set_sensitive (action, TRUE); */
1605 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1606 gtk_widget_set_sensitive (widget, TRUE);
1611 on_msg_count_changed (ModestHeaderView *header_view,
1613 TnyFolderChange *change,
1614 ModestMainWindow *main_window)
1616 gboolean refilter = FALSE;
1617 gboolean folder_empty = FALSE;
1618 gboolean all_marked_as_deleted = FALSE;
1619 ModestMainWindowPrivate *priv;
1621 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1622 g_return_if_fail (TNY_IS_FOLDER(folder));
1623 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1625 if (change != NULL) {
1626 TnyFolderChangeChanged changed;
1628 changed = tny_folder_change_get_changed (change);
1629 /* If something changes */
1630 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1631 folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
1633 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
1635 /* Play a sound (if configured) and make the LED blink */
1636 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1637 modest_platform_push_email_notification ();
1640 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
1643 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
1646 /* Check if all messages are marked to be deleted */
1647 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1648 folder_empty = folder_empty || all_marked_as_deleted;
1650 /* Set contents style of headers view */
1651 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY ||
1652 priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1654 modest_main_window_set_contents_style (main_window,
1655 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1656 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1658 modest_main_window_set_contents_style (main_window,
1659 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1664 modest_header_view_refilter (header_view);
1669 modest_main_window_set_contents_style (ModestMainWindow *self,
1670 ModestMainWindowContentsStyle style)
1672 ModestMainWindowPrivate *priv;
1674 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1676 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1678 /* We allow to set the same content style than the previously
1679 set if there are details, because it could happen when we're
1680 selecting different accounts consecutively */
1681 if ((priv->contents_style == style) &&
1682 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1685 /* Remove previous child. Delete it if it was an account
1687 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1689 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1690 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1693 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1696 priv->contents_style = style;
1698 switch (priv->contents_style) {
1699 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_FOLDERS:
1700 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->folder_view));
1701 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1703 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1705 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1706 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1707 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1709 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1710 gtk_widget_show (GTK_WIDGET (priv->header_view));
1712 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1713 g_message ("This view is not supported in Fremantle style");
1715 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1716 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1717 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1719 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1720 gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
1723 g_return_if_reached ();
1727 gtk_widget_show_all (priv->contents_widget);
1730 ModestMainWindowContentsStyle
1731 modest_main_window_get_contents_style (ModestMainWindow *self)
1733 ModestMainWindowPrivate *priv;
1735 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1737 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1738 return priv->contents_style;
1743 on_configuration_key_changed (ModestConf* conf,
1745 ModestConfEvent event,
1746 ModestConfNotificationId id,
1747 ModestMainWindow *self)
1749 /* TODO: remove this handler. Now we don't support details view,
1750 * so this must be removed */
1756 set_toolbar_transfer_mode (ModestMainWindow *self)
1758 ModestMainWindowPrivate *priv = NULL;
1760 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1762 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1764 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1766 if (priv->progress_bar_timeout > 0) {
1767 g_source_remove (priv->progress_bar_timeout);
1768 priv->progress_bar_timeout = 0;
1775 set_toolbar_mode (ModestMainWindow *self,
1776 ModestToolBarModes mode)
1778 ModestWindowPrivate *parent_priv = NULL;
1779 ModestMainWindowPrivate *priv = NULL;
1780 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1782 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1784 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1785 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1787 /* In case this was called before the toolbar exists: */
1788 if (!(parent_priv->toolbar))
1791 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1793 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1794 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1795 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1797 /* Sets current toolbar mode */
1798 priv->current_toolbar_mode = mode;
1800 /* Checks the dimming rules */
1801 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1802 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1804 /* Show and hide toolbar items */
1806 case TOOLBAR_MODE_NORMAL:
1808 gtk_action_set_visible (sort_action, TRUE);
1810 gtk_action_set_visible (refresh_action, TRUE);
1811 if (priv->progress_toolitem) {
1812 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1813 gtk_widget_hide (priv->progress_toolitem);
1815 if (priv->progress_bar)
1816 gtk_widget_hide (priv->progress_bar);
1819 gtk_action_set_visible (cancel_action, FALSE);
1821 /* Hide toolbar if optimized view is enabled */
1822 if (priv->optimized_view)
1823 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1825 case TOOLBAR_MODE_TRANSFER:
1827 gtk_action_set_visible (sort_action, FALSE);
1829 gtk_action_set_visible (refresh_action, FALSE);
1831 gtk_action_set_visible (cancel_action, TRUE);
1832 if (priv->progress_bar)
1833 gtk_widget_show (priv->progress_bar);
1834 if (priv->progress_toolitem) {
1835 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1836 gtk_widget_show (priv->progress_toolitem);
1839 /* Show toolbar if it's hiden (optimized view ) */
1840 if (priv->optimized_view)
1841 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1844 g_return_if_reached ();
1849 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
1851 ModestMainWindowPrivate *priv;
1853 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1854 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1856 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1860 cancel_progressbar (GtkToolButton *toolbutton,
1861 ModestMainWindow *self)
1864 ModestMainWindowPrivate *priv;
1866 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1868 /* Get operation observers and cancel all the operations */
1869 tmp = priv->progress_widgets;
1871 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1872 tmp=g_slist_next(tmp);
1877 observers_empty (ModestMainWindow *self)
1880 ModestMainWindowPrivate *priv;
1881 gboolean is_empty = TRUE;
1882 guint pending_ops = 0;
1884 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1885 tmp = priv->progress_widgets;
1887 /* Check all observers */
1888 while (tmp && is_empty) {
1889 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1890 is_empty = pending_ops == 0;
1892 tmp = g_slist_next(tmp);
1900 * Gets the toolbar mode needed for each mail operation. It stores in
1901 * @mode_changed if the toolbar mode has changed or not
1903 static ModestToolBarModes
1904 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
1905 ModestMailOperation *mail_op,
1906 gboolean *mode_changed)
1908 ModestToolBarModes mode;
1909 ModestMainWindowPrivate *priv;
1911 *mode_changed = FALSE;
1912 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1914 /* Get toolbar mode from operation id*/
1915 switch (modest_mail_operation_get_type_operation (mail_op)) {
1916 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
1917 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1918 mode = TOOLBAR_MODE_TRANSFER;
1919 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1920 *mode_changed = TRUE;
1923 mode = TOOLBAR_MODE_NORMAL;
1929 on_mail_operation_started (ModestMailOperation *mail_op,
1932 ModestMainWindow *self;
1933 ModestMailOperationTypeOperation op_type;
1934 ModestMainWindowPrivate *priv;
1935 ModestToolBarModes mode;
1937 gboolean mode_changed = FALSE;
1938 TnyAccount *account = NULL;
1940 self = MODEST_MAIN_WINDOW (user_data);
1941 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1943 /* Do not show progress for receiving operations if the
1944 account is the local account or the MMC one */
1945 op_type = modest_mail_operation_get_type_operation (mail_op);
1946 account = modest_mail_operation_get_account (mail_op);
1947 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
1950 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
1951 modest_tny_account_is_memory_card_account (account));
1953 g_object_unref (account);
1957 /* Show information banner. Remove old timeout */
1958 if (priv->opening_banner_timeout > 0) {
1959 g_source_remove (priv->opening_banner_timeout);
1960 priv->opening_banner_timeout = 0;
1962 /* Create a new timeout */
1963 priv->opening_banner_timeout =
1964 g_timeout_add (2000, show_opening_banner, self);
1967 /* Not every mail operation has account, noop does not */
1969 g_object_unref (account);
1971 /* Get toolbar mode from operation id*/
1972 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
1974 /* Add operation observers and change toolbar if neccessary*/
1975 tmp = priv->progress_widgets;
1976 if (mode == TOOLBAR_MODE_TRANSFER) {
1978 GObject *source = modest_mail_operation_get_source(mail_op);
1979 if (G_OBJECT (self) == source) {
1980 set_toolbar_transfer_mode(self);
1982 g_object_unref (source);
1986 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1988 tmp = g_slist_next (tmp);
1992 /* Update the main menu as well, we need to explicitely do
1993 this in order to enable/disable accelerators */
1994 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1998 on_mail_operation_finished (ModestMailOperation *mail_op,
2001 ModestToolBarModes mode;
2002 ModestMailOperationTypeOperation op_type;
2004 ModestMainWindow *self;
2005 gboolean mode_changed;
2006 TnyAccount *account = NULL;
2007 ModestMainWindowPrivate *priv;
2009 self = MODEST_MAIN_WINDOW (user_data);
2010 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2012 /* The mail operation was not added to the progress objects if
2013 the account was the local account or the MMC one */
2014 op_type = modest_mail_operation_get_type_operation (mail_op);
2015 account = modest_mail_operation_get_account (mail_op);
2016 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2019 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2020 modest_tny_account_is_memory_card_account (account));
2022 g_object_unref (account);
2026 /* Remove old timeout */
2027 if (priv->opening_banner_timeout > 0) {
2028 g_source_remove (priv->opening_banner_timeout);
2029 priv->opening_banner_timeout = 0;
2032 /* Remove the banner if exists */
2033 if (priv->opening_banner) {
2034 gtk_widget_destroy (priv->opening_banner);
2035 priv->opening_banner = NULL;
2039 /* Not every mail operation has account, noop does not */
2041 g_object_unref (account);
2043 /* Get toolbar mode from operation id*/
2044 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2046 /* Change toolbar mode */
2047 tmp = priv->progress_widgets;
2048 if (mode == TOOLBAR_MODE_TRANSFER) {
2050 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2052 tmp = g_slist_next (tmp);
2055 /* If no more operations are being observed, NORMAL mode is enabled again */
2056 if (observers_empty (self)) {
2057 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2063 on_queue_changed (ModestMailOperationQueue *queue,
2064 ModestMailOperation *mail_op,
2065 ModestMailOperationQueueNotification type,
2066 ModestMainWindow *self)
2068 ModestMainWindowPrivate *priv;
2070 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2072 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2073 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2075 "operation-started",
2076 G_CALLBACK (on_mail_operation_started),
2078 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2080 "operation-finished",
2081 G_CALLBACK (on_mail_operation_finished),
2083 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2084 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2086 "operation-started");
2087 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2089 "operation-finished");
2094 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2096 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2098 ModestAccountMgr *mgr;
2099 ModestAccountSettings *settings;
2100 ModestServerAccountSettings *store_settings = NULL;
2102 GtkWidget *folder_window;
2104 folder_window = GTK_WIDGET (modest_folder_window_new (NULL));
2105 modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2106 MODEST_WINDOW (folder_window),
2107 MODEST_WINDOW (self));
2108 gtk_widget_show (folder_window);
2110 /* Get account data */
2111 mgr = modest_runtime_get_account_mgr ();
2112 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2114 store_settings = modest_account_settings_get_store_settings (settings);
2116 /* Set the new visible & active account */
2117 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2118 const gchar *account_name;
2120 account_name = modest_account_settings_get_account_name (settings);
2122 modest_folder_view_set_account_id_of_visible_server_account
2124 modest_server_account_settings_get_account_name (store_settings));
2125 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2126 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2128 modest_folder_window_set_account (MODEST_FOLDER_WINDOW (folder_window), acc_name);
2130 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2131 if (action != NULL) {
2132 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2133 modest_utils_toggle_action_set_active_block_notify (
2134 GTK_TOGGLE_ACTION (action),
2142 g_object_unref (store_settings);
2143 g_object_unref (settings);
2148 /* Make sure that at least one account is "viewed": */
2150 set_at_least_one_account_visible(ModestMainWindow *self)
2152 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2153 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2155 if (!(priv->folder_view)) {
2156 /* It is too early to do this. */
2160 const gchar *active_server_account_name =
2161 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2163 if (!active_server_account_name ||
2164 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2166 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2167 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2168 if (default_modest_name) {
2169 set_account_visible (self, default_modest_name);
2170 } else if (first_modest_name) {
2171 set_account_visible (self, first_modest_name);
2173 g_free (first_modest_name);
2174 g_free (default_modest_name);
2179 on_show_account_action_toggled (GtkToggleAction *action,
2182 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2184 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2185 if (gtk_toggle_action_get_active (action))
2186 set_account_visible (self, acc_name);
2190 refresh_account (const gchar *account_name)
2194 /* win must already exists here, obviously */
2195 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2198 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2202 /* If account_name == NULL, we must update all (option All) */
2204 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2206 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2211 on_refresh_account_action_activated (GtkAction *action,
2214 refresh_account ((const gchar*) user_data);
2218 on_send_receive_csm_activated (GtkMenuItem *item,
2221 refresh_account ((const gchar*) user_data);
2225 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2227 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2229 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2235 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2237 ModestMainWindow *main_window = NULL;
2239 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2240 main_window = MODEST_MAIN_WINDOW (userdata);
2242 /* Update toolbar dimming state */
2243 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2244 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2250 on_header_view_focus_in (GtkWidget *widget,
2251 GdkEventFocus *event,
2254 ModestMainWindow *main_window = NULL;
2256 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2258 main_window = MODEST_MAIN_WINDOW (userdata);
2260 /* Update toolbar dimming state */
2261 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2262 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2268 on_folder_selection_changed (ModestFolderView *folder_view,
2269 TnyFolderStore *folder_store,
2271 ModestMainWindow *main_window)
2273 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2274 GtkAction *action = NULL;
2275 gboolean show_reply = TRUE;
2276 gboolean show_forward = TRUE;
2277 gboolean show_cancel_send = FALSE;
2278 gboolean show_clipboard = TRUE;
2279 gboolean show_delete = TRUE;
2282 if (TNY_IS_ACCOUNT (folder_store)) {
2283 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2284 } else if (TNY_IS_FOLDER (folder_store)) {
2285 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2286 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2287 TNY_FOLDER (folder_store));
2288 switch (folder_type) {
2289 case TNY_FOLDER_TYPE_DRAFTS:
2290 show_clipboard = show_delete = TRUE;
2291 show_reply = show_forward = show_cancel_send = FALSE;
2293 case TNY_FOLDER_TYPE_SENT:
2294 show_forward = show_clipboard = show_delete = TRUE;
2295 show_reply = show_cancel_send = FALSE;
2297 case TNY_FOLDER_TYPE_OUTBOX:
2298 show_clipboard = show_delete = show_cancel_send = TRUE;
2299 show_reply = show_forward = FALSE;
2301 case TNY_FOLDER_TYPE_INVALID:
2302 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2305 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2306 show_cancel_send = FALSE;
2309 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2310 show_cancel_send = FALSE;
2315 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2316 gtk_action_set_visible (action, show_reply);
2317 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2318 gtk_action_set_visible (action, show_reply);
2319 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2320 gtk_action_set_visible (action, show_forward);
2321 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2322 gtk_action_set_visible (action, show_cancel_send);
2323 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2324 gtk_action_set_visible (action, show_delete);
2329 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2330 GtkTreeModel *model,
2331 GtkTreeRowReference *row_reference,
2332 ModestMainWindow *self)
2334 ModestMainWindowPrivate *priv = NULL;
2335 GtkTreeModel *header_model = NULL;
2336 GtkTreePath *path = NULL;
2338 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2339 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2340 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2342 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2343 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2345 /* Do nothing if we changed the folder in the main view */
2346 if (header_model != model)
2349 /* Select the message in the header view */
2350 path = gtk_tree_row_reference_get_path (row_reference);
2351 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2353 gtk_tree_path_free (path);
2359 updating_banner_destroyed (gpointer data,
2360 GObject *where_the_object_was)
2362 ModestMainWindowPrivate *priv = NULL;
2364 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2366 priv->updating_banner = NULL;
2370 show_updating_banner (gpointer user_data)
2372 ModestMainWindowPrivate *priv = NULL;
2374 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2376 if (priv->updating_banner == NULL) {
2378 /* We're outside the main lock */
2379 gdk_threads_enter ();
2380 priv->updating_banner =
2381 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2382 _CS ("ckdg_pb_updating"));
2384 /* We need this because banners in Maemo could be
2385 destroyed by dialogs so we need to properly update
2386 our reference to it */
2387 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2388 updating_banner_destroyed,
2390 gdk_threads_leave ();
2393 /* Remove timeout */
2394 priv->updating_banner_timeout = 0;
2399 * We use this function to show/hide a progress banner showing
2400 * "Updating" while the header view is being filled. We're not showing
2401 * it unless the update takes more than 2 seconds
2403 * If starting = TRUE then the refresh is starting, otherwise it means
2404 * that is has just finished
2407 on_updating_msg_list (ModestHeaderView *header_view,
2411 ModestMainWindowPrivate *priv = NULL;
2413 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2415 /* Remove old timeout */
2416 if (priv->updating_banner_timeout > 0) {
2417 g_source_remove (priv->updating_banner_timeout);
2418 priv->updating_banner_timeout = 0;
2421 /* Create a new timeout */
2423 priv->updating_banner_timeout =
2424 g_timeout_add (2000, show_updating_banner, user_data);
2426 /* Remove the banner if exists */
2427 if (priv->updating_banner) {
2428 gtk_widget_destroy (priv->updating_banner);
2429 priv->updating_banner = NULL;
2434 static void on_folder_view_row_activated (GtkTreeView *tree_view,
2435 GtkTreePath *tree_path,
2436 GtkTreeViewColumn *column,
2439 GtkTreeModel *model;
2441 TnyFolderStore *folder_store = NULL;
2442 ModestMainWindow *self = (ModestMainWindow *) userdata;
2443 ModestMainWindowPrivate *priv = NULL;
2445 g_return_if_fail (MODEST_IS_MAIN_WINDOW(self));
2446 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2448 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
2450 if (gtk_tree_model_get_iter (model, &iter, tree_path)) {
2451 gtk_tree_model_get (model, &iter,
2452 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder_store,
2454 if (folder_store && TNY_IS_FOLDER (folder_store)) {
2455 modest_header_view_set_folder (MODEST_HEADER_VIEW (priv->header_view),
2456 TNY_FOLDER (folder_store), TRUE,
2458 modest_main_window_set_contents_style (MODEST_MAIN_WINDOW (self),
2459 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2460 modest_widget_memory_restore (modest_runtime_get_conf (),
2461 G_OBJECT(priv->header_view),
2462 MODEST_CONF_HEADER_VIEW_KEY);
2463 on_msg_count_changed (MODEST_HEADER_VIEW (priv->header_view), TNY_FOLDER (folder_store), NULL, self);
2467 g_object_unref (folder_store);
2470 g_message ("FOLDER VIEW CELL ACTIVATED");
2475 modest_main_window_screen_is_on (ModestMainWindow *self)
2477 ModestMainWindowPrivate *priv = NULL;
2479 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2481 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2483 return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2487 remove_banners (ModestMainWindow *window)
2489 ModestMainWindowPrivate *priv;
2491 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2493 if (priv->opening_banner_timeout > 0) {
2494 g_source_remove (priv->opening_banner_timeout);
2495 priv->opening_banner_timeout = 0;
2498 if (priv->opening_banner != NULL) {
2499 gtk_widget_destroy (priv->opening_banner);
2500 priv->opening_banner = NULL;
2503 if (priv->updating_banner_timeout > 0) {
2504 g_source_remove (priv->updating_banner_timeout);
2505 priv->updating_banner_timeout = 0;
2508 if (priv->updating_banner != NULL) {
2509 gtk_widget_destroy (priv->updating_banner);
2510 priv->updating_banner = NULL;
2516 on_window_hide (GObject *gobject,
2520 g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
2522 if (!GTK_WIDGET_VISIBLE (gobject)) {
2523 TnyFolderStore *folder_store;
2524 ModestMainWindowPrivate *priv;
2526 /* Remove the currently shown banners */
2527 remove_banners (MODEST_MAIN_WINDOW (gobject));
2529 /* Force the folder view to sync the currently selected folder
2530 to save the read/unread status and to expunge messages */
2531 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
2532 folder_store = modest_folder_view_get_selected (priv->folder_view);
2533 if (TNY_IS_FOLDER (folder_store)) {
2534 ModestMailOperation *mail_op;
2536 mail_op = modest_mail_operation_new (NULL);
2537 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2539 modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
2540 g_object_unref (mail_op);
2541 g_object_unref (folder_store);
2547 on_window_destroy (GtkObject *widget,
2550 g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
2552 remove_banners (MODEST_MAIN_WINDOW (widget));
2556 opening_banner_destroyed (gpointer data,
2557 GObject *where_the_object_was)
2559 ModestMainWindowPrivate *priv = NULL;
2561 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2563 priv->opening_banner = NULL;
2567 show_opening_banner (gpointer user_data)
2569 ModestMainWindowPrivate *priv = NULL;
2571 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2573 if (priv->opening_banner == NULL) {
2575 /* We're outside the main lock */
2576 gdk_threads_enter ();
2577 priv->opening_banner =
2578 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2579 _("mail_me_opening"));
2581 /* We need this because banners in Maemo could be
2582 destroyed by dialogs so we need to properly update
2583 our reference to it */
2584 g_object_weak_ref (G_OBJECT (priv->opening_banner),
2585 opening_banner_destroyed,
2588 /* We need this because banners in Maemo could be
2589 destroyed by dialogs so we need to properly update
2590 our reference to it */
2591 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2592 updating_banner_destroyed,
2594 gdk_threads_leave ();
2597 /* Remove timeout */
2598 priv->opening_banner_timeout = 0;