1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-utils.h>
57 #include <modest-maemo-utils.h>
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-mail-operation.h"
61 #include "modest-icon-names.h"
62 #include "modest-progress-bar.h"
63 #include "modest-text-utils.h"
64 #include "modest-ui-dimming-manager.h"
65 #include "maemo/modest-osso-state-saving.h"
66 #include "modest-text-utils.h"
67 #include "modest-signal-mgr.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 gboolean modest_main_window_window_state_event (GtkWidget *widget,
82 GdkEventWindowState *event,
85 static void connect_signals (ModestMainWindow *self);
87 static void modest_main_window_disconnect_signals (ModestWindow *self);
89 static void restore_settings (ModestMainWindow *self,
90 gboolean do_folder_view_too);
92 static void save_state (ModestWindow *self);
94 static void update_menus (ModestMainWindow* self);
96 static void modest_main_window_show_toolbar (ModestWindow *window,
97 gboolean show_toolbar);
99 static void cancel_progressbar (GtkToolButton *toolbutton,
100 ModestMainWindow *self);
102 static void on_queue_changed (ModestMailOperationQueue *queue,
103 ModestMailOperation *mail_op,
104 ModestMailOperationQueueNotification type,
105 ModestMainWindow *self);
107 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
109 static void on_account_inserted (TnyAccountStore *accoust_store,
113 static void on_account_removed (TnyAccountStore *accoust_store,
117 static void on_account_changed (TnyAccountStore *account_store,
121 static void on_default_account_changed (ModestAccountMgr* mgr,
124 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
128 static void on_configuration_key_changed (ModestConf* conf,
130 ModestConfEvent event,
131 ModestConfNotificationId id,
132 ModestMainWindow *self);
134 static void set_toolbar_mode (ModestMainWindow *self,
135 ModestToolBarModes mode);
137 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
139 static void on_show_account_action_toggled (GtkToggleAction *action,
142 static void on_refresh_account_action_activated (GtkAction *action,
145 static void on_send_receive_csm_activated (GtkMenuItem *item,
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 restore_paned_timeout_handler (gpointer *data);
179 static gboolean show_retrieving_banner (gpointer user_data);
181 static void on_window_destroy (GtkObject *widget,
184 static void on_window_hide (GObject *gobject,
188 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
189 struct _ModestMainWindowPrivate {
190 GtkWidget *msg_paned;
191 GtkWidget *main_paned;
192 GtkWidget *main_vbox;
193 GtkWidget *contents_widget;
194 GtkWidget *empty_view;
196 /* Progress observers */
197 GtkWidget *progress_bar;
198 GSList *progress_widgets;
201 GtkWidget *progress_toolitem;
202 GtkWidget *cancel_toolitem;
203 GtkWidget *sort_toolitem;
204 GtkWidget *refresh_toolitem;
205 ModestToolBarModes current_toolbar_mode;
207 /* Merge ids used to add/remove accounts to the ViewMenu*/
208 GByteArray *merge_ids;
209 GtkActionGroup *view_additions_group;
211 /* On-demand widgets */
212 GtkWidget *accounts_popup;
213 GtkWidget *details_widget;
215 /* Optimized view enabled */
216 gboolean optimized_view;
218 /* Optimized view enabled */
219 gboolean send_receive_in_progress;
221 ModestHeaderView *header_view;
222 ModestFolderView *folder_view;
224 ModestMainWindowStyle style;
225 ModestMainWindowContentsStyle contents_style;
226 gboolean wait_for_settings;
228 guint progress_bar_timeout;
229 guint restore_paned_timeout;
231 /* Signal handler UIDs */
232 GList *queue_err_signals;
235 /* "Updating" banner for header view */
236 GtkWidget *updating_banner;
237 guint updating_banner_timeout;
239 /* "Retrieving" banner for header view */
240 GtkWidget *retrieving_banner;
241 guint retrieving_banner_timeout;
244 osso_display_state_t display_state;
246 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
247 MODEST_TYPE_MAIN_WINDOW, \
248 ModestMainWindowPrivate))
250 typedef struct _GetMsgAsyncHelper {
251 ModestMainWindowPrivate *main_window_private;
253 ModestTnyMsgReplyType reply_type;
254 ModestTnyMsgForwardType forward_type;
261 static GtkWindowClass *parent_class = NULL;
264 /* Private actions */
265 /* This is the context sensitive menu: */
266 static const GtkActionEntry modest_folder_view_action_entries [] = {
268 /* Folder View CSM actions */
269 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
270 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
271 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
272 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
273 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
274 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_csm_help) },
277 static const GtkActionEntry modest_header_view_action_entries [] = {
279 /* Header View CSM actions */
280 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
281 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
282 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
283 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
284 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
285 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
286 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
287 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
288 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
289 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
292 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
293 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
296 /************************************************************************/
299 modest_main_window_get_type (void)
301 static GType my_type = 0;
303 static const GTypeInfo my_info = {
304 sizeof(ModestMainWindowClass),
305 NULL, /* base init */
306 NULL, /* base finalize */
307 (GClassInitFunc) modest_main_window_class_init,
308 NULL, /* class finalize */
309 NULL, /* class data */
310 sizeof(ModestMainWindow),
312 (GInstanceInitFunc) modest_main_window_init,
315 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
323 modest_main_window_class_init (ModestMainWindowClass *klass)
325 GObjectClass *gobject_class;
326 gobject_class = (GObjectClass*) klass;
327 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
329 parent_class = g_type_class_peek_parent (klass);
330 gobject_class->finalize = modest_main_window_finalize;
332 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
334 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
335 modest_window_class->save_state_func = save_state;
336 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
337 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
338 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
342 modest_main_window_init (ModestMainWindow *obj)
344 ModestMainWindowPrivate *priv;
346 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
348 priv->queue_err_signals = NULL;
349 priv->msg_paned = NULL;
350 priv->main_paned = NULL;
351 priv->main_vbox = NULL;
352 priv->header_view = NULL;
353 priv->folder_view = NULL;
354 priv->contents_widget = NULL;
355 priv->accounts_popup = NULL;
356 priv->details_widget = NULL;
357 priv->empty_view = NULL;
358 priv->progress_widgets = NULL;
359 priv->progress_bar = NULL;
360 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
361 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
362 priv->wait_for_settings = TRUE;
363 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
364 priv->merge_ids = NULL;
365 priv->optimized_view = FALSE;
366 priv->send_receive_in_progress = FALSE;
367 priv->progress_bar_timeout = 0;
368 priv->restore_paned_timeout = 0;
369 priv->sighandlers = NULL;
370 priv->updating_banner = NULL;
371 priv->updating_banner_timeout = 0;
372 priv->retrieving_banner = NULL;
373 priv->retrieving_banner_timeout = 0;
374 priv->display_state = OSSO_DISPLAY_ON;
376 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
378 "applications_email_mainview");
382 modest_main_window_finalize (GObject *obj)
384 ModestMainWindowPrivate *priv;
386 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
388 /* Sanity check: shouldn't be needed, the window mgr should
389 call this function before */
390 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
391 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
393 if (priv->empty_view) {
394 g_object_unref (priv->empty_view);
395 priv->empty_view = NULL;
398 if (priv->header_view) {
399 g_object_unref (priv->header_view);
400 priv->header_view = NULL;
403 g_slist_free (priv->progress_widgets);
405 g_byte_array_free (priv->merge_ids, TRUE);
407 if (priv->progress_bar_timeout > 0) {
408 g_source_remove (priv->progress_bar_timeout);
409 priv->progress_bar_timeout = 0;
412 if (priv->updating_banner_timeout > 0) {
413 g_source_remove (priv->updating_banner_timeout);
414 priv->updating_banner_timeout = 0;
417 if (priv->updating_banner) {
418 gtk_widget_destroy (priv->updating_banner);
419 priv->updating_banner = NULL;
422 if (priv->retrieving_banner_timeout > 0) {
423 g_source_remove (priv->retrieving_banner_timeout);
424 priv->retrieving_banner_timeout = 0;
427 if (priv->retrieving_banner) {
428 gtk_widget_destroy (priv->retrieving_banner);
429 priv->retrieving_banner = NULL;
432 if (priv->restore_paned_timeout > 0) {
433 g_source_remove (priv->restore_paned_timeout);
434 priv->restore_paned_timeout = 0;
437 G_OBJECT_CLASS(parent_class)->finalize (obj);
441 modest_main_window_get_child_widget (ModestMainWindow *self,
442 ModestMainWindowWidgetType widget_type)
444 ModestMainWindowPrivate *priv;
447 g_return_val_if_fail (self && MODEST_IS_MAIN_WINDOW(self), NULL);
448 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
451 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
453 switch (widget_type) {
454 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
455 widget = (GtkWidget*)priv->header_view; break;
456 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
457 widget = (GtkWidget*)priv->folder_view; break;
462 /* Note that the window could have been destroyed, and so
463 their children, but still have some references */
464 return (widget && GTK_IS_WIDGET(widget)) ? GTK_WIDGET(widget) : NULL;
468 restore_paned_timeout_handler (gpointer *data)
470 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
471 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
474 /* Timeouts are outside the main lock */
475 gdk_threads_enter ();
476 if (GTK_WIDGET_VISIBLE (main_window)) {
477 conf = modest_runtime_get_conf ();
478 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
479 MODEST_CONF_MAIN_PANED_KEY);
481 gdk_threads_leave ();
488 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
491 ModestMainWindowPrivate *priv;
493 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
495 conf = modest_runtime_get_conf ();
497 modest_widget_memory_restore (conf, G_OBJECT(self),
498 MODEST_CONF_MAIN_WINDOW_KEY);
500 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
501 MODEST_CONF_HEADER_VIEW_KEY);
503 if (do_folder_view_too)
504 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
505 MODEST_CONF_FOLDER_VIEW_KEY);
507 /* modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned), */
508 /* MODEST_CONF_MAIN_PANED_KEY); */
510 g_timeout_add (250, (GSourceFunc) restore_paned_timeout_handler, self);
512 /* We need to force a redraw here in order to get the right
513 position of the horizontal paned separator */
514 gtk_widget_show (GTK_WIDGET (self));
519 save_state (ModestWindow *window)
522 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
523 ModestMainWindowPrivate *priv;
525 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
526 conf = modest_runtime_get_conf ();
528 modest_widget_memory_save (conf,G_OBJECT(self),
529 MODEST_CONF_MAIN_WINDOW_KEY);
530 /* Only save main paned position if we're in split mode */
531 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
532 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
533 MODEST_CONF_MAIN_PANED_KEY);
534 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
535 MODEST_CONF_FOLDER_VIEW_KEY);
539 compare_display_names (ModestAccountSettings *a,
540 ModestAccountSettings *b)
542 return g_utf8_collate (modest_account_settings_get_display_name (a),
543 modest_account_settings_get_display_name (b));
547 /* We use this function to prevent the send&receive CSM to be shown
548 when there are less than two account */
550 tap_and_hold_query_cb (GtkWidget *widget, GdkEvent *event)
556 update_menus (ModestMainWindow* self)
558 GSList *account_names, *iter, *accounts;
559 ModestMainWindowPrivate *priv;
560 ModestWindowPrivate *parent_priv;
561 ModestAccountMgr *mgr;
562 gint i, num_accounts;
564 gchar *default_account;
565 const gchar *active_account_name;
566 GtkWidget *send_receive_button, *item;
567 GtkAction *send_receive_all = NULL;
570 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
571 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
573 /* Get enabled account IDs */
574 mgr = modest_runtime_get_account_mgr ();
575 account_names = modest_account_mgr_account_names (mgr, TRUE);
576 iter = account_names;
580 ModestAccountSettings *settings =
581 modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
582 accounts = g_slist_prepend (accounts, settings);
586 modest_account_mgr_free_account_names (account_names);
587 account_names = NULL;
589 /* Order the list of accounts by its display name */
590 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
591 num_accounts = g_slist_length (accounts);
593 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
594 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
595 gtk_action_set_visible (send_receive_all, num_accounts > 0);
597 /* Delete old send&receive popup items. We can not just do a
598 menu_detach because it does not work well with
600 if (priv->accounts_popup)
601 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
602 (GtkCallback) gtk_widget_destroy, NULL);
604 /* Delete old entries in the View menu. Do not free groups, it
606 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
608 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
609 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
610 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
611 GTK_ACTION_GROUP (groups->data));
614 if (priv->merge_ids) {
615 for (i = 0; i < priv->merge_ids->len; i++)
616 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
617 g_byte_array_free (priv->merge_ids, TRUE);
619 /* We need to call this in order to ensure
620 that the new actions are added in the right
621 order (alphabetical) */
622 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
624 groups = g_list_next (groups);
626 priv->merge_ids = g_byte_array_sized_new (num_accounts);
628 /* Get send receive button */
629 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
630 "/ToolBar/ToolbarSendReceive");
632 /* Create the menu */
633 if (num_accounts > 1) {
634 if (!priv->accounts_popup)
635 priv->accounts_popup = gtk_menu_new ();
636 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
637 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
638 g_signal_connect (G_OBJECT (item),
640 G_CALLBACK (on_send_receive_csm_activated),
642 item = gtk_separator_menu_item_new ();
643 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
646 /* Create a new action group */
647 default_account = modest_account_mgr_get_default_account (mgr);
648 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
650 if (!active_account_name)
651 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
653 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
655 for (i = 0; i < num_accounts; i++) {
656 gchar *display_name = NULL;
657 const gchar *account_name;
658 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
661 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
664 account_name = modest_account_settings_get_account_name (settings);
666 if (default_account && account_name &&
667 !(strcmp (default_account, account_name) == 0)) {
668 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
669 modest_account_settings_get_display_name (settings));
671 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
672 modest_account_settings_get_display_name (settings));
677 /* Create action and add it to the action group. The
678 action name must be the account name, this way we
679 could know in the handlers the account to show */
680 if (settings && account_name) {
681 gchar* item_name, *refresh_action_name;
683 GtkAction *view_account_action, *refresh_account_action;
684 gchar *escaped_display_name;
686 escaped_display_name = modest_text_utils_escape_mnemonics (display_name);
688 view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
689 escaped_display_name, NULL, NULL, 0));
690 g_free (escaped_display_name);
691 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
692 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
693 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
695 if (active_account_name) {
696 if (active_account_name && account_name &&
697 (strcmp (active_account_name, account_name) == 0)) {
698 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
702 /* Add ui from account data. We allow 2^9-1 account
703 changes in a single execution because we're
704 downcasting the guint to a guint8 in order to use a
705 GByteArray. It should be enough :-) */
706 item_name = g_strconcat (account_name, "Menu", NULL);
707 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
708 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
709 gtk_ui_manager_add_ui (parent_priv->ui_manager,
711 "/MenuBar/ViewMenu/ViewMenuAdditions",
714 GTK_UI_MANAGER_MENUITEM,
717 /* Connect the action signal "activate" */
718 g_signal_connect_after (G_OBJECT (view_account_action),
720 G_CALLBACK (on_show_account_action_toggled),
723 /* Create the items for the Tools->Send&Receive submenu */
724 refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
725 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
726 display_name, NULL, NULL);
727 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
729 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
730 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
731 gtk_ui_manager_add_ui (parent_priv->ui_manager,
733 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
736 GTK_UI_MANAGER_MENUITEM,
738 g_free (refresh_action_name);
740 g_signal_connect_data (G_OBJECT (refresh_account_action),
742 G_CALLBACK (on_refresh_account_action_activated),
743 g_strdup (account_name),
744 (GClosureNotify) g_free,
747 /* Create item and add it to the send&receive
748 CSM. If there is only one account then
750 if (num_accounts > 1) {
751 GtkWidget *label = gtk_label_new(NULL);
752 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
753 if (default_account && (strcmp(account_name, default_account) == 0)) {
754 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
755 gtk_label_set_markup (GTK_LABEL (label), escaped);
758 gtk_label_set_text (GTK_LABEL (label), display_name);
761 item = gtk_menu_item_new ();
762 gtk_container_add (GTK_CONTAINER (item), label);
764 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup),
766 g_signal_connect_data (G_OBJECT (item),
768 G_CALLBACK (on_send_receive_csm_activated),
769 g_strdup (account_name),
770 (GClosureNotify) g_free,
777 g_free (display_name);
780 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
782 /* We cannot do this in the loop above because this relies on the action
783 * group being inserted. This makes the default account appear in bold.
784 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
785 for (i = 0; i < num_accounts; i++) {
786 gchar *item_name, *path;
788 ModestAccountSettings *settings;
789 const gchar *account_name;
792 settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
793 account_name = modest_account_settings_get_account_name (settings);
794 is_default = (account_name && default_account && !strcmp (account_name, default_account));
796 /* Get the item of the view menu */
797 item_name = g_strconcat (account_name, "Menu", NULL);
798 path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
799 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
803 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
804 if (GTK_IS_LABEL (child)) {
805 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
807 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
808 gtk_label_set_markup (GTK_LABEL (child), bold_name);
811 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
815 /* Get the item of the tools menu */
816 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
817 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
821 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
822 if (GTK_IS_LABEL (child)) {
823 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
825 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
826 gtk_label_set_markup (GTK_LABEL (child), bold_name);
829 gtk_label_set_ellipsize (GTK_LABEL (child), PANGO_ELLIPSIZE_END);
834 g_object_unref (settings);
837 if (num_accounts > 1) {
838 /* Disconnect the tap-and-hold-query if it's connected */
839 if (modest_signal_mgr_is_connected (priv->sighandlers,
840 G_OBJECT (send_receive_button),
841 "tap-and-hold-query"))
842 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
843 G_OBJECT (send_receive_button),
844 "tap-and-hold-query");
846 /* Mandatory in order to view the menu contents */
847 gtk_widget_show_all (priv->accounts_popup);
849 /* Setup tap_and_hold just if was not done before*/
850 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
851 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
853 /* Connect the tap-and-hold-query in order not to show the CSM */
854 if (!modest_signal_mgr_is_connected (priv->sighandlers,
855 G_OBJECT (send_receive_button),
856 "tap-and-hold-query"))
857 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
858 G_OBJECT (send_receive_button),
859 "tap-and-hold-query",
860 G_CALLBACK (tap_and_hold_query_cb),
865 g_slist_free (accounts);
866 g_free (default_account);
869 /* Make sure that at least one account is viewed if there are any
870 * accounts, for instance when adding the first account: */
871 set_at_least_one_account_visible (self);
875 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
877 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
878 gtk_scrolled_window_add_with_viewport
879 (GTK_SCROLLED_WINDOW(win), widget);
881 gtk_container_add (GTK_CONTAINER(win),
892 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
894 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
896 GList *oerrsignals = priv->queue_err_signals;
897 while (oerrsignals) {
898 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
899 g_signal_handler_disconnect (esignal->queue, esignal->signal);
900 g_slice_free (QueueErrorSignal, esignal);
901 oerrsignals = g_list_next (oerrsignals);
903 g_list_free (priv->queue_err_signals);
904 priv->queue_err_signals = NULL;
909 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
911 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
914 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
918 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
920 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
922 /* Update visibility */
925 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW(user_data));
929 modest_main_window_disconnect_signals (ModestWindow *self)
931 ModestMainWindowPrivate *priv;
932 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
934 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
935 priv->sighandlers = NULL;
939 connect_signals (ModestMainWindow *self)
941 ModestWindowPrivate *parent_priv;
942 ModestMainWindowPrivate *priv;
945 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
946 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
951 modest_signal_mgr_connect (priv->sighandlers,
952 G_OBJECT(priv->folder_view), "key-press-event",
953 G_CALLBACK(on_inner_widgets_key_pressed), self);
955 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
956 "folder_selection_changed",
957 G_CALLBACK (on_folder_selection_changed),
960 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
961 "folder-display-name-changed",
962 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
965 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
967 G_CALLBACK (on_folder_view_focus_in),
970 /* Folder view CSM */
971 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
972 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
973 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
974 G_CALLBACK(_folder_view_csm_menu_activated),
978 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
979 G_CALLBACK(modest_ui_actions_on_header_selected), self);
981 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
982 G_CALLBACK(modest_ui_actions_on_header_activated), self);
984 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
985 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
987 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
988 G_CALLBACK(on_inner_widgets_key_pressed), self);
990 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
991 G_CALLBACK(on_msg_count_changed), self);
993 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
994 G_CALLBACK (on_header_view_focus_in), self);
996 modest_signal_mgr_connect (priv->sighandlers,
997 G_OBJECT (priv->header_view),
999 G_CALLBACK (on_updating_msg_list),
1002 /* Header view CSM */
1003 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
1004 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
1006 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
1007 G_CALLBACK(_header_view_csm_menu_activated),
1012 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
1013 G_CALLBACK (modest_main_window_window_state_event),
1015 /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
1016 * in destroy stage */
1017 g_signal_connect (G_OBJECT (self), "destroy", G_CALLBACK (on_window_destroy), NULL);
1019 g_signal_connect (G_OBJECT (self), "notify::visible", G_CALLBACK (on_window_hide), NULL);
1021 /* Mail Operation Queue */
1023 modest_signal_mgr_connect (priv->sighandlers,
1024 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
1026 G_CALLBACK (on_queue_changed), self);
1028 /* Track changes in the device name */
1030 modest_signal_mgr_connect (priv->sighandlers,
1031 G_OBJECT(modest_runtime_get_conf ()),
1033 G_CALLBACK (on_configuration_key_changed),
1036 /* Track account changes. We need to refresh the toolbar */
1038 modest_signal_mgr_connect (priv->sighandlers,
1039 G_OBJECT (modest_runtime_get_account_store ()),
1041 G_CALLBACK (on_account_inserted),
1044 modest_signal_mgr_connect (priv->sighandlers,
1045 G_OBJECT (modest_runtime_get_account_store ()),
1047 G_CALLBACK (on_account_removed),
1050 /* We need to refresh the send & receive menu to change the bold
1051 * account when the default account changes. */
1053 modest_signal_mgr_connect (priv->sighandlers,
1054 G_OBJECT (modest_runtime_get_account_mgr ()),
1055 "default_account_changed",
1056 G_CALLBACK (on_default_account_changed),
1061 modest_signal_mgr_connect (priv->sighandlers,
1062 G_OBJECT (modest_runtime_get_account_store ()),
1064 G_CALLBACK (on_account_changed),
1069 on_hildon_program_is_topmost_notify(GObject *self,
1070 GParamSpec *propert_param,
1073 HildonProgram *app = HILDON_PROGRAM (self);
1075 /* Note that use of hildon_program_set_can_hibernate()
1076 * is generally referred to as "setting the killable flag",
1077 * though hibernation does not seem equal to death.
1080 if (hildon_program_get_is_topmost (app)) {
1081 /* Prevent hibernation when the progam comes to the foreground,
1082 * because hibernation should only happen when the application
1083 * is in the background: */
1084 hildon_program_set_can_hibernate (app, FALSE);
1086 /* Remove new mail visual notifications */
1087 modest_platform_remove_new_mail_notifications (TRUE);
1089 /* Allow hibernation if the program has gone to the background: */
1091 /* However, prevent hibernation while the settings are being changed: */
1092 const gboolean hibernation_prevented =
1093 modest_window_mgr_get_hibernation_is_prevented (
1094 modest_runtime_get_window_mgr ());
1096 if (hibernation_prevented)
1097 hildon_program_set_can_hibernate (app, FALSE);
1099 /* Allow hibernation, after saving the state: */
1100 modest_osso_save_state();
1101 hildon_program_set_can_hibernate (app, TRUE);
1108 GtkWidget *folder_win;
1113 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1115 ShowHelper *helper = (ShowHelper *) user_data;
1116 GtkWidget *folder_win = helper->folder_win;
1117 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1119 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1120 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1122 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1124 /* Connect signals */
1125 connect_signals (MODEST_MAIN_WINDOW (self));
1127 /* Set account store */
1128 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1129 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1131 /* Load previous osso state, for instance if we are being restored from
1133 modest_osso_load_state ();
1135 /* Restore window & widget settings */
1136 priv->wait_for_settings = TRUE;
1137 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1138 priv->wait_for_settings = FALSE;
1140 /* Check if accounts exist and show the account wizard if not */
1141 gboolean accounts_exist =
1142 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1144 if (!accounts_exist) {
1145 /* This is necessary to have the main window shown behind the dialog
1146 It's an ugly hack... jschmid */
1147 gtk_widget_show_all(GTK_WIDGET(self));
1148 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1150 update_menus (MODEST_MAIN_WINDOW (self));
1153 /* Never call this function again (NOTE that it could happen
1154 as we hide the main window instead of closing it while
1155 there are operations ongoing) and free the helper */
1156 g_signal_handler_disconnect (self, helper->handler_id);
1157 g_slice_free (ShowHelper, helper);
1161 osso_display_event_cb (osso_display_state_t state,
1164 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1166 priv->display_state = state;
1168 /* Stop blinking if the screen becomes on */
1169 if (priv->display_state == OSSO_DISPLAY_ON)
1170 modest_platform_remove_new_mail_notifications (TRUE);
1174 modest_main_window_new (void)
1176 ModestMainWindow *self = NULL;
1177 ModestMainWindowPrivate *priv = NULL;
1178 ModestWindowPrivate *parent_priv = NULL;
1179 GtkWidget *folder_win = NULL;
1180 ModestDimmingRulesGroup *menu_rules_group = NULL;
1181 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1182 GtkActionGroup *action_group = NULL;
1183 GError *error = NULL;
1185 ModestConf *conf = NULL;
1186 GtkAction *action = NULL;
1187 GdkPixbuf *window_icon;
1190 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1191 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1192 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1194 parent_priv->ui_manager = gtk_ui_manager_new();
1195 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1197 action_group = gtk_action_group_new ("ModestMainWindowActions");
1198 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1200 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1201 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1203 /* Add common actions */
1204 gtk_action_group_add_actions (action_group,
1205 modest_action_entries,
1206 G_N_ELEMENTS (modest_action_entries),
1209 gtk_action_group_add_actions (action_group,
1210 modest_folder_view_action_entries,
1211 G_N_ELEMENTS (modest_folder_view_action_entries),
1214 gtk_action_group_add_actions (action_group,
1215 modest_header_view_action_entries,
1216 G_N_ELEMENTS (modest_header_view_action_entries),
1219 gtk_action_group_add_toggle_actions (action_group,
1220 modest_toggle_action_entries,
1221 G_N_ELEMENTS (modest_toggle_action_entries),
1224 gtk_action_group_add_toggle_actions (action_group,
1225 modest_main_window_toggle_action_entries,
1226 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1229 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1230 g_object_unref (action_group);
1232 /* Load the UI definition */
1233 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1234 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1235 if (error != NULL) {
1236 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1237 g_error_free (error);
1241 /* Add common dimming rules */
1242 modest_dimming_rules_group_add_rules (menu_rules_group,
1243 modest_main_window_menu_dimming_entries,
1244 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1245 MODEST_WINDOW (self));
1246 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1247 modest_main_window_toolbar_dimming_entries,
1248 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1249 MODEST_WINDOW (self));
1251 /* Insert dimming rules group for this window */
1252 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1253 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1254 g_object_unref (menu_rules_group);
1255 g_object_unref (toolbar_rules_group);
1257 /* Add accelerators */
1258 gtk_window_add_accel_group (GTK_WINDOW (self),
1259 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1261 /* Menubar. Update the state of some toggles */
1262 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1263 conf = modest_runtime_get_conf ();
1264 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1265 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1266 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1267 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1268 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1269 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1270 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1271 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1272 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1273 gtk_widget_show (parent_priv->menubar);
1275 /* Get device name */
1276 modest_maemo_utils_get_device_name ();
1280 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1281 g_object_ref (priv->header_view);
1282 if (!priv->header_view)
1283 g_printerr ("modest: cannot instantiate header view\n");
1284 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1285 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1286 MODEST_CONF_HEADER_VIEW_KEY);
1288 /* Other style properties of header view */
1289 g_object_set (G_OBJECT (priv->header_view),
1290 "rules-hint", FALSE,
1292 /* gtk_widget_show (priv->header_view); */
1295 priv->empty_view = create_empty_view ();
1296 gtk_widget_show (priv->empty_view);
1297 g_object_ref (priv->empty_view);
1299 /* Create scrolled windows */
1300 folder_win = gtk_scrolled_window_new (NULL, NULL);
1301 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1302 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1304 GTK_POLICY_AUTOMATIC);
1305 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1307 GTK_POLICY_AUTOMATIC);
1308 /* gtk_widget_show (priv->contents_widget); */
1311 priv->main_paned = gtk_hpaned_new ();
1312 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1313 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1314 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1316 /* putting it all together... */
1317 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1318 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1319 gtk_widget_show (priv->main_vbox);
1321 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1323 app = hildon_program_get_instance ();
1324 hildon_program_add_window (app, HILDON_WINDOW (self));
1326 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1327 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1329 /* Connect to "show" action. We delay the creation of some
1330 elements until that moment */
1331 helper = g_slice_new0 (ShowHelper);
1332 helper->folder_win = folder_win;
1333 helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1334 G_CALLBACK (modest_main_window_on_show),
1337 /* Set window icon */
1338 window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1340 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1341 g_object_unref (window_icon);
1344 /* Listen for changes in the screen, we don't want to show a
1345 led pattern when the display is on for example */
1346 osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1347 osso_display_event_cb,
1350 /* Dont't restore settings here,
1351 * because it requires a gtk_widget_show(),
1352 * and we don't want to do that until later,
1353 * so that the UI is not visible for non-menu D-Bus activation.
1356 return MODEST_WINDOW(self);
1360 modest_main_window_set_style (ModestMainWindow *self,
1361 ModestMainWindowStyle style)
1363 ModestMainWindowPrivate *priv;
1364 ModestWindowPrivate *parent_priv;
1367 GtkTreeSelection *sel;
1370 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1372 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1373 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1375 /* no change -> nothing to do */
1376 if (priv->style == style)
1379 /* Get toggle button and update the state if needed. This will
1380 happen only when the set_style is not invoked from the UI,
1381 for example when it's called from widget memory */
1382 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1383 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1384 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1385 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1386 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1387 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1388 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1391 /* We need to store the selection because it's lost when the
1392 widget is reparented */
1393 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1394 rows = gtk_tree_selection_get_selected_rows (sel, NULL);
1396 priv->style = style;
1398 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1400 if (!priv->wait_for_settings)
1401 modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT (priv->main_paned),
1402 MODEST_CONF_MAIN_PANED_KEY);
1403 /* Remove main paned */
1404 g_object_ref (priv->main_paned);
1405 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1407 /* Reparent the contents widget to the main vbox */
1408 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1411 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1412 /* Remove header view */
1413 g_object_ref (priv->contents_widget);
1414 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1416 /* Reparent the main paned */
1417 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1418 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1420 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
1424 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1426 g_return_if_reached ();
1429 /* Reselect the previously selected folders. We disable the
1430 dimming rules execution during that time because there is
1431 no need to work out it again and it could take a lot of
1432 time if all the headers are selected */
1434 modest_window_disable_dimming (MODEST_WINDOW (self));
1436 gtk_tree_selection_select_path (sel, (GtkTreePath *) list->data);
1437 list = g_list_next (list);
1439 modest_window_enable_dimming (MODEST_WINDOW (self));
1442 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1445 /* Let header view grab the focus if it's being shown */
1446 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1447 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1449 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
1450 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1452 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1455 /* Check dimming rules */
1456 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1457 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1460 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1463 ModestMainWindowStyle
1464 modest_main_window_get_style (ModestMainWindow *self)
1466 ModestMainWindowPrivate *priv;
1468 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1470 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1475 toolbar_resize (ModestMainWindow *self)
1477 ModestMainWindowPrivate *priv = NULL;
1478 ModestWindowPrivate *parent_priv = NULL;
1480 gint static_button_size;
1481 ModestWindowMgr *mgr;
1483 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1484 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1485 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1487 mgr = modest_runtime_get_window_mgr ();
1488 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1490 if (parent_priv->toolbar) {
1491 /* left size buttons */
1492 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1493 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1494 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1495 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1496 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1497 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1498 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1499 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1500 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1501 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1502 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1503 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1504 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1505 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1506 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1507 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1509 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1510 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1511 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1512 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1513 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1514 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1515 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1516 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1524 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1526 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1527 ModestWindowPrivate *parent_priv;
1528 ModestWindowMgr *mgr;
1529 gboolean is_fullscreen;
1530 GtkAction *fs_toggle_action;
1533 mgr = modest_runtime_get_window_mgr ();
1535 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1537 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1539 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1540 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1541 if (is_fullscreen != active) {
1542 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1545 toolbar_resize (MODEST_MAIN_WINDOW (widget));
1553 modest_main_window_show_toolbar (ModestWindow *self,
1554 gboolean show_toolbar)
1556 ModestMainWindowPrivate *priv = NULL;
1557 ModestWindowPrivate *parent_priv = NULL;
1558 GtkWidget *reply_button = NULL, *menu = NULL;
1559 GtkWidget *placeholder = NULL;
1561 const gchar *action_name;
1564 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1565 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1566 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1568 /* Set optimized view status */
1569 priv->optimized_view = !show_toolbar;
1571 if (!parent_priv->toolbar) {
1572 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1574 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1576 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1577 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1578 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1579 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1580 toolbar_resize (MODEST_MAIN_WINDOW (self));
1582 /* Add ProgressBar (Transfer toolbar) */
1583 priv->progress_bar = modest_progress_bar_new ();
1584 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1585 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1586 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1587 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1588 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1590 /* Connect cancel 'clicked' signal to abort progress mode */
1591 g_signal_connect(priv->cancel_toolitem, "clicked",
1592 G_CALLBACK(cancel_progressbar),
1595 /* Add it to the observers list */
1596 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1599 hildon_window_add_toolbar (HILDON_WINDOW (self),
1600 GTK_TOOLBAR (parent_priv->toolbar));
1602 /* Set reply button tap and hold menu */
1603 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1604 "/ToolBar/ToolbarMessageReply");
1605 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1606 "/ToolbarReplyCSM");
1607 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1609 /* Set send & receive button tap and hold menu */
1610 update_menus (MODEST_MAIN_WINDOW (self));
1614 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1615 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1616 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1618 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1619 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1620 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1622 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1624 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1628 /* Update also the actions (to update the toggles in the
1629 menus), we have to do it manually because some other window
1630 of the same time could have changed it (remember that the
1631 toolbar fullscreen mode is shared by all the windows of the
1633 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1634 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1636 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1638 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1639 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1644 on_account_inserted (TnyAccountStore *accoust_store,
1645 TnyAccount *account,
1648 /* Transport accounts and local ones (MMC and the Local
1649 folders account do now cause menu changes */
1650 if (TNY_IS_STORE_ACCOUNT (account) &&
1651 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1653 update_menus (MODEST_MAIN_WINDOW (user_data));
1658 on_default_account_changed (ModestAccountMgr* mgr,
1661 update_menus (MODEST_MAIN_WINDOW (user_data));
1665 on_account_removed (TnyAccountStore *accoust_store,
1666 TnyAccount *account,
1669 /* Transport accounts and local ones (MMC and the Local
1670 folders account do now cause menu changes */
1671 if (TNY_IS_STORE_ACCOUNT (account) &&
1672 modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1673 update_menus (MODEST_MAIN_WINDOW (user_data));
1677 on_account_changed (TnyAccountStore *account_store,
1678 TnyAccount *account,
1681 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1683 /* Transport accounts and local ones (MMC and the Local
1684 folders account do now cause menu changes */
1685 if (TNY_IS_STORE_ACCOUNT (account)) {
1686 /* We need to refresh the details widget because it could have changed */
1687 if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1688 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1690 /* Update the menus as well, name could change */
1691 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1692 update_menus (MODEST_MAIN_WINDOW (user_data));
1697 * This function manages the key events used to navigate between
1698 * header and folder views (when the window is in split view)
1701 * -------------------------------------------------
1702 * HeaderView GDK_Left Move focus to folder view
1703 * FolderView GDK_Right Move focus to header view
1705 * There is no need to scroll to selected row, the widgets will be the
1706 * responsibles of doing that (probably managing the focus-in event
1709 on_inner_widgets_key_pressed (GtkWidget *widget,
1713 ModestMainWindowPrivate *priv;
1715 if (event->type == GDK_KEY_RELEASE)
1718 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1720 /* Do nothing if we're in SIMPLE style */
1721 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1724 if (MODEST_IS_HEADER_VIEW (widget)) {
1725 if (event->keyval == GDK_Left)
1726 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1727 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1728 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1729 if (selected_headers > 1) {
1730 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1733 GtkTreePath * cursor_path;
1734 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1735 if (cursor_path == NULL) {
1736 GtkTreeSelection *selection;
1738 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1739 list = gtk_tree_selection_get_selected_rows (selection, NULL);
1742 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1743 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1748 } else if (MODEST_IS_FOLDER_VIEW (widget) && (event->keyval == GDK_Right || event->keyval == GDK_Left)) {
1749 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1750 GtkTreePath *selected_path = NULL;
1751 GtkTreePath *start_path = NULL;
1752 GtkTreePath *end_path = NULL;
1754 GtkTreeSelection *selection;
1756 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1757 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1758 if (selected != NULL) {
1759 selected_path = (GtkTreePath *) selected->data;
1760 if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1764 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1765 (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1767 /* Scroll to first path */
1768 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1777 gtk_tree_path_free (start_path);
1779 gtk_tree_path_free (end_path);
1780 g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1781 g_list_free (selected);
1783 #endif /* GTK_CHECK_VERSION */
1785 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1792 set_alignment (GtkWidget *widget,
1795 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1796 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1800 create_empty_view (void)
1802 GtkLabel *label = NULL;
1803 GtkWidget *align = NULL;
1805 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1806 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1807 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1808 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1810 return GTK_WIDGET(align);
1814 * Free the returned string
1817 get_gray_color_markup (GtkWidget *styled_widget)
1819 gchar *gray_color_markup = NULL;
1820 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1821 /* Obtain the secondary text color. We need a realized widget, that's why
1822 we get styled_widget from outside */
1824 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1825 gray_color_markup = modest_text_utils_get_color_string (&color);
1826 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1828 if (!gray_color_markup)
1829 gray_color_markup = g_strdup ("#BBBBBB");
1831 return gray_color_markup;
1835 * Free the returned string
1838 create_device_name_visual_string (const gchar *device_name,
1839 const gchar *gray_color_markup)
1843 /* We have to use "" to fill the %s of the translation. We can
1844 not just use the device name because the device name is
1845 shown in a different color, so it could not be included
1846 into the <span> tag */
1847 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1848 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1859 GtkWidget *count_label;
1860 GtkWidget *msg_count_label;
1861 GtkWidget *size_label;
1862 gchar *color_markup;
1866 create_uint_label (const gchar *markup,
1870 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", markup, name, count);
1874 create_gchar_label (const gchar *markup,
1878 return g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", markup, name, count);
1882 update_folder_stats_status_cb (ModestFolderStats stats,
1885 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1888 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_folders"), stats.folders);
1889 gtk_label_set_markup (GTK_LABEL (widgets->count_label), label);
1892 label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_messages"), stats.msg_count);
1893 gtk_label_set_markup (GTK_LABEL (widgets->msg_count_label), label);
1896 if (widgets->size_label) {
1897 tmp = modest_text_utils_get_display_size (stats.local_size);
1898 label = create_gchar_label (widgets->color_markup, _("mcen_fi_rootfolder_size"), tmp);
1899 gtk_label_set_markup (GTK_LABEL (widgets->size_label), label);
1906 update_folder_stats_cb (ModestFolderStats stats,
1909 DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1912 update_folder_stats_status_cb (stats, user_data);
1914 /* frees. Note that the widgets could have been destroyed but
1915 we still keep a reference */
1916 g_free (widgets->color_markup);
1917 if (widgets->count_label)
1918 g_object_unref (widgets->count_label);
1919 if (widgets->msg_count_label)
1920 g_object_unref (widgets->msg_count_label);
1921 if (widgets->size_label)
1922 g_object_unref (widgets->size_label);
1923 g_slice_free (DetailsWidgets, widgets);
1927 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1929 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1934 gchar *gray_color_markup;
1935 DetailsWidgets *widgets;
1937 vbox = gtk_vbox_new (FALSE, 0);
1938 widgets = g_slice_new0 (DetailsWidgets);
1940 gray_color_markup = get_gray_color_markup (styled_widget);
1941 widgets->color_markup = g_strdup (gray_color_markup);
1943 /* Account description: */
1944 if (modest_tny_account_is_virtual_local_folders (account)
1945 || (modest_tny_account_is_memory_card_account (account))) {
1947 /* Get device name */
1948 gchar *device_name = NULL;
1949 if (modest_tny_account_is_virtual_local_folders (account))
1950 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1951 MODEST_CONF_DEVICE_NAME, NULL);
1953 device_name = g_strdup (tny_account_get_name (account));
1955 label = create_device_name_visual_string ((const gchar *) device_name,
1956 (const gchar *) gray_color_markup);
1957 label_w = gtk_label_new (NULL);
1958 gtk_label_set_markup (GTK_LABEL (label_w), label);
1959 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1960 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1961 g_free (device_name);
1964 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1965 gtk_box_pack_start (GTK_BOX (vbox),
1966 gtk_label_new (tny_account_get_name (account)),
1969 /* Other accounts, such as IMAP and POP: */
1974 /* Put proto in uppercase */
1975 proto = g_string_new (tny_account_get_proto (account));
1976 proto = g_string_ascii_up (proto);
1978 /* note: mcen_fi_localroot_description is something like "%s account"
1979 * however, we should display "%s account: %s"... therefore, ugly tmp */
1980 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1981 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1982 gray_color_markup, tmp, tny_account_get_name (account));
1985 label_w = gtk_label_new (NULL);
1986 gtk_label_set_markup (GTK_LABEL (label_w), label);
1987 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
1988 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1989 g_string_free (proto, TRUE);
1995 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1996 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_messages"), 0);
1997 label_w = gtk_label_new (NULL);
1998 gtk_label_set_markup (GTK_LABEL (label_w), label);
1999 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2000 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2003 widgets->msg_count_label = g_object_ref (label_w);
2006 label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_folders"), 0);
2007 label_w = gtk_label_new (NULL);
2008 gtk_label_set_markup (GTK_LABEL (label_w), label);
2009 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2010 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2013 widgets->count_label = g_object_ref (label_w);
2016 if (modest_tny_account_is_virtual_local_folders (account)
2017 || modest_tny_account_is_memory_card_account (account)) {
2019 label = create_gchar_label (gray_color_markup, _("mcen_fi_rootfolder_size"), "0");
2021 label_w = gtk_label_new (NULL);
2022 gtk_label_set_markup (GTK_LABEL (label_w), label);
2023 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2024 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2027 widgets->size_label = g_object_ref (label_w);
2029 } else if (TNY_IS_ACCOUNT(folder_store)) {
2030 TnyAccount *account = TNY_ACCOUNT(folder_store);
2032 time_t last_updated;
2033 const gchar *last_updated_string;
2034 /* Get last updated from configuration */
2035 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
2036 tny_account_get_id (account));
2038 if (last_updated > 0)
2039 last_updated_string = modest_text_utils_get_display_date(last_updated);
2041 last_updated_string = g_strdup (_("mcen_va_never"));
2043 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
2044 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
2045 label_w = gtk_label_new (NULL);
2046 gtk_label_set_markup (GTK_LABEL (label_w), label);
2047 gtk_label_set_ellipsize (GTK_LABEL (label_w), PANGO_ELLIPSIZE_END);
2048 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2052 g_free (gray_color_markup);
2054 /* Refresh folder stats asynchronously */
2055 modest_tny_folder_store_get_folder_stats (TNY_FOLDER_STORE (account),
2056 update_folder_stats_cb,
2057 update_folder_stats_status_cb,
2061 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
2067 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
2069 ModestMainWindowPrivate *priv = NULL;
2071 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2073 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2075 return priv->send_receive_in_progress;
2079 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
2081 GtkAction *action = NULL;
2082 GtkWidget *widget = NULL;
2083 ModestMainWindowPrivate *priv = NULL;
2085 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2086 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2088 priv->send_receive_in_progress = TRUE;
2090 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2091 gtk_action_set_sensitive (action, FALSE);
2092 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2093 /* gtk_action_set_sensitive (action, FALSE); */
2094 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2095 gtk_widget_set_sensitive (widget, FALSE);
2099 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
2101 GtkAction *action = NULL;
2102 GtkWidget *widget = NULL;
2103 ModestMainWindowPrivate *priv = NULL;
2105 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2106 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2108 priv->send_receive_in_progress = FALSE;
2110 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
2111 gtk_action_set_sensitive (action, TRUE);
2112 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2113 /* gtk_action_set_sensitive (action, TRUE); */
2114 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
2115 gtk_widget_set_sensitive (widget, TRUE);
2120 on_msg_count_changed (ModestHeaderView *header_view,
2122 TnyFolderChange *change,
2123 ModestMainWindow *main_window)
2125 gboolean refilter = FALSE;
2126 gboolean folder_empty = FALSE;
2127 gboolean all_marked_as_deleted = FALSE;
2128 ModestMainWindowPrivate *priv;
2130 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
2131 g_return_if_fail (TNY_IS_FOLDER(folder));
2132 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2134 if (change != NULL) {
2135 TnyFolderChangeChanged changed;
2137 changed = tny_folder_change_get_changed (change);
2138 /* If something changes */
2139 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
2140 folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
2142 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2144 /* Play a sound (if configured) and make the LED blink */
2145 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
2146 modest_platform_push_email_notification ();
2149 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
2152 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2155 /* Check if all messages are marked to be deleted */
2156 all_marked_as_deleted = modest_header_view_is_empty (header_view);
2157 folder_empty = folder_empty || all_marked_as_deleted;
2159 /* Set contents style of headers view */
2161 modest_main_window_set_contents_style (main_window,
2162 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2163 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
2165 modest_main_window_set_contents_style (main_window,
2166 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2170 modest_header_view_refilter (header_view);
2175 modest_main_window_set_contents_style (ModestMainWindow *self,
2176 ModestMainWindowContentsStyle style)
2178 ModestMainWindowPrivate *priv;
2180 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2182 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2184 /* We allow to set the same content style than the previously
2185 set if there are details, because it could happen when we're
2186 selecting different accounts consecutively */
2187 if ((priv->contents_style == style) &&
2188 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
2191 /* Remove previous child. Delete it if it was an account
2193 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
2195 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
2196 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
2199 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
2202 priv->contents_style = style;
2204 switch (priv->contents_style) {
2205 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
2206 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
2207 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2210 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
2212 /* if we're started without main win, there may not be a folder
2213 * view. this fixes a GLib-Critical */
2214 if (priv->folder_view) {
2215 TnyFolderStore *selected_folderstore =
2216 modest_folder_view_get_selected (priv->folder_view);
2217 if (TNY_IS_ACCOUNT (selected_folderstore)) {
2218 priv->details_widget = create_details_widget (GTK_WIDGET (self),
2219 TNY_ACCOUNT (selected_folderstore));
2221 wrap_in_scrolled_window (priv->contents_widget,
2222 priv->details_widget);
2224 g_object_unref (selected_folderstore);
2225 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2230 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
2231 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
2232 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2236 g_return_if_reached ();
2240 gtk_widget_show_all (priv->contents_widget);
2243 ModestMainWindowContentsStyle
2244 modest_main_window_get_contents_style (ModestMainWindow *self)
2246 ModestMainWindowPrivate *priv;
2248 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
2250 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2251 return priv->contents_style;
2256 on_configuration_key_changed (ModestConf* conf,
2258 ModestConfEvent event,
2259 ModestConfNotificationId id,
2260 ModestMainWindow *self)
2262 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2263 TnyAccount *account = NULL;
2265 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
2268 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
2271 if (priv->folder_view)
2272 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
2274 if (account && TNY_IS_ACCOUNT (account) &&
2275 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
2278 const gchar *device_name;
2279 gchar *new_text, *gray_color_markup;
2282 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
2283 label = GTK_LABEL (children->data);
2285 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2286 MODEST_CONF_DEVICE_NAME, NULL);
2288 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
2289 new_text = create_device_name_visual_string (device_name, gray_color_markup);
2291 gtk_label_set_markup (label, new_text);
2292 gtk_widget_show (GTK_WIDGET (label));
2294 g_free (gray_color_markup);
2296 g_list_free (children);
2298 g_object_unref (account);
2302 set_toolbar_transfer_mode (ModestMainWindow *self)
2304 ModestMainWindowPrivate *priv = NULL;
2306 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2308 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2310 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2312 if (priv->progress_bar_timeout > 0) {
2313 g_source_remove (priv->progress_bar_timeout);
2314 priv->progress_bar_timeout = 0;
2321 set_toolbar_mode (ModestMainWindow *self,
2322 ModestToolBarModes mode)
2324 ModestWindowPrivate *parent_priv = NULL;
2325 ModestMainWindowPrivate *priv = NULL;
2326 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2328 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2330 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2331 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2333 /* In case this was called before the toolbar exists: */
2334 if (!(parent_priv->toolbar))
2337 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2339 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2340 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2341 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2343 /* Sets current toolbar mode */
2344 priv->current_toolbar_mode = mode;
2346 /* Checks the dimming rules */
2347 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2348 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2350 /* Show and hide toolbar items */
2352 case TOOLBAR_MODE_NORMAL:
2354 gtk_action_set_visible (sort_action, TRUE);
2356 gtk_action_set_visible (refresh_action, TRUE);
2357 if (priv->progress_toolitem) {
2358 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2359 gtk_widget_hide (priv->progress_toolitem);
2361 if (priv->progress_bar)
2362 gtk_widget_hide (priv->progress_bar);
2365 gtk_action_set_visible (cancel_action, FALSE);
2367 /* Hide toolbar if optimized view is enabled */
2368 if (priv->optimized_view)
2369 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2371 case TOOLBAR_MODE_TRANSFER:
2373 gtk_action_set_visible (sort_action, FALSE);
2375 gtk_action_set_visible (refresh_action, FALSE);
2377 gtk_action_set_visible (cancel_action, TRUE);
2378 if (priv->progress_bar)
2379 gtk_widget_show (priv->progress_bar);
2380 if (priv->progress_toolitem) {
2381 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2382 gtk_widget_show (priv->progress_toolitem);
2385 /* Show toolbar if it's hiden (optimized view ) */
2386 if (priv->optimized_view)
2387 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2390 g_return_if_reached ();
2395 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2397 ModestMainWindowPrivate *priv;
2399 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2400 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2402 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2406 cancel_progressbar (GtkToolButton *toolbutton,
2407 ModestMainWindow *self)
2410 ModestMainWindowPrivate *priv;
2412 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2414 /* Get operation observers and cancel all the operations */
2415 tmp = priv->progress_widgets;
2417 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2418 tmp=g_slist_next(tmp);
2423 observers_empty (ModestMainWindow *self)
2426 ModestMainWindowPrivate *priv;
2427 gboolean is_empty = TRUE;
2428 guint pending_ops = 0;
2430 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2431 tmp = priv->progress_widgets;
2433 /* Check all observers */
2434 while (tmp && is_empty) {
2435 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2436 is_empty = pending_ops == 0;
2438 tmp = g_slist_next(tmp);
2446 * Gets the toolbar mode needed for each mail operation. It stores in
2447 * @mode_changed if the toolbar mode has changed or not
2449 static ModestToolBarModes
2450 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2451 ModestMailOperation *mail_op,
2452 gboolean *mode_changed)
2454 ModestToolBarModes mode;
2455 ModestMainWindowPrivate *priv;
2457 *mode_changed = FALSE;
2458 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2460 /* Get toolbar mode from operation id*/
2461 switch (modest_mail_operation_get_type_operation (mail_op)) {
2462 case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
2463 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2464 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2465 mode = TOOLBAR_MODE_TRANSFER;
2466 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2467 *mode_changed = TRUE;
2470 mode = TOOLBAR_MODE_NORMAL;
2476 on_mail_operation_started (ModestMailOperation *mail_op,
2479 ModestMainWindow *self;
2480 ModestMailOperationTypeOperation op_type;
2481 ModestMainWindowPrivate *priv;
2482 ModestToolBarModes mode;
2484 gboolean mode_changed = FALSE;
2485 TnyAccount *account = NULL;
2487 self = MODEST_MAIN_WINDOW (user_data);
2488 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2490 /* Do not show progress for receiving operations if the
2491 account is the local account or the MMC one */
2492 op_type = modest_mail_operation_get_type_operation (mail_op);
2493 account = modest_mail_operation_get_account (mail_op);
2494 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2497 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2498 modest_tny_account_is_memory_card_account (account));
2500 g_object_unref (account);
2504 /* Show information banner. Remove old timeout */
2505 if (priv->retrieving_banner_timeout > 0) {
2506 g_source_remove (priv->retrieving_banner_timeout);
2507 priv->retrieving_banner_timeout = 0;
2509 /* Create a new timeout */
2510 priv->retrieving_banner_timeout =
2511 g_timeout_add (2000, show_retrieving_banner, self);
2514 /* Not every mail operation has account, noop does not */
2516 g_object_unref (account);
2518 /* Get toolbar mode from operation id*/
2519 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2521 /* Add operation observers and change toolbar if neccessary*/
2522 tmp = priv->progress_widgets;
2523 if (mode == TOOLBAR_MODE_TRANSFER) {
2525 GObject *source = modest_mail_operation_get_source(mail_op);
2526 if (G_OBJECT (self) == source) {
2527 set_toolbar_transfer_mode(self);
2529 g_object_unref (source);
2533 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2535 tmp = g_slist_next (tmp);
2539 /* Update the main menu as well, we need to explicitely do
2540 this in order to enable/disable accelerators */
2541 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2545 on_mail_operation_finished (ModestMailOperation *mail_op,
2548 ModestToolBarModes mode;
2549 ModestMailOperationTypeOperation op_type;
2551 ModestMainWindow *self;
2552 gboolean mode_changed;
2553 TnyAccount *account = NULL;
2554 ModestMainWindowPrivate *priv;
2556 self = MODEST_MAIN_WINDOW (user_data);
2557 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2559 /* The mail operation was not added to the progress objects if
2560 the account was the local account or the MMC one */
2561 op_type = modest_mail_operation_get_type_operation (mail_op);
2562 account = modest_mail_operation_get_account (mail_op);
2563 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2566 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2567 modest_tny_account_is_memory_card_account (account));
2569 g_object_unref (account);
2573 /* Remove old timeout */
2574 if (priv->retrieving_banner_timeout > 0) {
2575 g_source_remove (priv->retrieving_banner_timeout);
2576 priv->retrieving_banner_timeout = 0;
2579 /* Remove the banner if exists */
2580 if (priv->retrieving_banner) {
2581 gtk_widget_destroy (priv->retrieving_banner);
2582 priv->retrieving_banner = NULL;
2586 /* Not every mail operation has account, noop does not */
2588 g_object_unref (account);
2590 /* Get toolbar mode from operation id*/
2591 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2593 /* Change toolbar mode */
2594 tmp = priv->progress_widgets;
2595 if (mode == TOOLBAR_MODE_TRANSFER) {
2597 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2599 tmp = g_slist_next (tmp);
2602 /* If no more operations are being observed, NORMAL mode is enabled again */
2603 if (observers_empty (self)) {
2604 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2610 on_queue_changed (ModestMailOperationQueue *queue,
2611 ModestMailOperation *mail_op,
2612 ModestMailOperationQueueNotification type,
2613 ModestMainWindow *self)
2615 ModestMainWindowPrivate *priv;
2617 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2619 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2620 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2622 "operation-started",
2623 G_CALLBACK (on_mail_operation_started),
2625 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2627 "operation-finished",
2628 G_CALLBACK (on_mail_operation_finished),
2630 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2631 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2633 "operation-started");
2634 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2636 "operation-finished");
2641 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2643 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2645 ModestAccountMgr *mgr;
2646 ModestAccountSettings *settings;
2647 ModestServerAccountSettings *store_settings = NULL;
2649 /* Get account data */
2650 mgr = modest_runtime_get_account_mgr ();
2651 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2653 store_settings = modest_account_settings_get_store_settings (settings);
2655 /* Set the new visible & active account */
2656 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2657 const gchar *account_name;
2659 account_name = modest_account_settings_get_account_name (settings);
2661 modest_folder_view_set_account_id_of_visible_server_account
2663 modest_server_account_settings_get_account_name (store_settings));
2664 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2665 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2667 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2668 if (action != NULL) {
2669 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2670 modest_utils_toggle_action_set_active_block_notify (
2671 GTK_TOGGLE_ACTION (action),
2679 g_object_unref (store_settings);
2680 g_object_unref (settings);
2684 /* Make sure that at least one account is "viewed": */
2686 set_at_least_one_account_visible(ModestMainWindow *self)
2688 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2689 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2691 if (!(priv->folder_view)) {
2692 /* It is too early to do this. */
2696 const gchar *active_server_account_name =
2697 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2699 if (!active_server_account_name ||
2700 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2702 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2703 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2704 if (default_modest_name) {
2705 set_account_visible (self, default_modest_name);
2706 } else if (first_modest_name) {
2707 set_account_visible (self, first_modest_name);
2709 g_free (first_modest_name);
2710 g_free (default_modest_name);
2715 on_show_account_action_toggled (GtkToggleAction *action,
2718 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2720 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2721 if (gtk_toggle_action_get_active (action))
2722 set_account_visible (self, acc_name);
2726 refresh_account (const gchar *account_name)
2730 /* win must already exists here, obviously */
2731 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2734 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2738 /* If account_name == NULL, we must update all (option All) */
2740 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2742 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2747 on_refresh_account_action_activated (GtkAction *action,
2750 refresh_account ((const gchar*) user_data);
2754 on_send_receive_csm_activated (GtkMenuItem *item,
2757 refresh_account ((const gchar*) user_data);
2761 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2763 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2765 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2771 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2773 ModestMainWindow *main_window = NULL;
2775 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2776 main_window = MODEST_MAIN_WINDOW (userdata);
2778 /* Update toolbar dimming state */
2779 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2780 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2786 on_header_view_focus_in (GtkWidget *widget,
2787 GdkEventFocus *event,
2790 ModestMainWindow *main_window = NULL;
2792 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2794 main_window = MODEST_MAIN_WINDOW (userdata);
2796 /* Update toolbar dimming state */
2797 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2798 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2804 on_folder_selection_changed (ModestFolderView *folder_view,
2805 TnyFolderStore *folder_store,
2807 ModestMainWindow *main_window)
2809 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2810 GtkAction *action = NULL;
2811 gboolean show_reply = TRUE;
2812 gboolean show_forward = TRUE;
2813 gboolean show_cancel_send = FALSE;
2814 gboolean show_clipboard = TRUE;
2815 gboolean show_delete = TRUE;
2818 if (TNY_IS_ACCOUNT (folder_store)) {
2819 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2820 } else if (TNY_IS_FOLDER (folder_store)) {
2821 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2822 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2823 TNY_FOLDER (folder_store));
2824 switch (folder_type) {
2825 case TNY_FOLDER_TYPE_DRAFTS:
2826 show_clipboard = show_delete = TRUE;
2827 show_reply = show_forward = show_cancel_send = FALSE;
2829 case TNY_FOLDER_TYPE_SENT:
2830 show_forward = show_clipboard = show_delete = TRUE;
2831 show_reply = show_cancel_send = FALSE;
2833 case TNY_FOLDER_TYPE_OUTBOX:
2834 show_clipboard = show_delete = show_cancel_send = TRUE;
2835 show_reply = show_forward = FALSE;
2837 case TNY_FOLDER_TYPE_INVALID:
2838 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2841 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2842 show_cancel_send = FALSE;
2845 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2846 show_cancel_send = FALSE;
2851 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2852 gtk_action_set_visible (action, show_reply);
2853 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2854 gtk_action_set_visible (action, show_reply);
2855 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2856 gtk_action_set_visible (action, show_forward);
2857 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2858 gtk_action_set_visible (action, show_cancel_send);
2859 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2860 gtk_action_set_visible (action, show_delete);
2862 /* We finally call to the ui actions handler, after updating properly
2863 * the header view CSM */
2864 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2868 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2869 GtkTreeModel *model,
2870 GtkTreeRowReference *row_reference,
2871 ModestMainWindow *self)
2873 ModestMainWindowPrivate *priv = NULL;
2874 GtkTreeModel *header_model = NULL;
2875 GtkTreePath *path = NULL;
2877 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2878 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2879 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2881 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2882 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2884 /* Do nothing if we changed the folder in the main view */
2885 if (header_model != model)
2888 /* Select the message in the header view */
2889 path = gtk_tree_row_reference_get_path (row_reference);
2890 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2892 gtk_tree_path_free (path);
2898 updating_banner_destroyed (gpointer data,
2899 GObject *where_the_object_was)
2901 ModestMainWindowPrivate *priv = NULL;
2903 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2905 priv->updating_banner = NULL;
2909 show_updating_banner (gpointer user_data)
2911 ModestMainWindowPrivate *priv = NULL;
2913 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2915 if (priv->updating_banner == NULL) {
2917 /* We're outside the main lock */
2918 gdk_threads_enter ();
2919 priv->updating_banner =
2920 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2921 _CS ("ckdg_pb_updating"));
2923 /* We need this because banners in Maemo could be
2924 destroyed by dialogs so we need to properly update
2925 our reference to it */
2926 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2927 updating_banner_destroyed,
2929 gdk_threads_leave ();
2932 /* Remove timeout */
2933 priv->updating_banner_timeout = 0;
2938 * We use this function to show/hide a progress banner showing
2939 * "Updating" while the header view is being filled. We're not showing
2940 * it unless the update takes more than 2 seconds
2942 * If starting = TRUE then the refresh is starting, otherwise it means
2943 * that is has just finished
2946 on_updating_msg_list (ModestHeaderView *header_view,
2950 ModestMainWindowPrivate *priv = NULL;
2952 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2954 /* Remove old timeout */
2955 if (priv->updating_banner_timeout > 0) {
2956 g_source_remove (priv->updating_banner_timeout);
2957 priv->updating_banner_timeout = 0;
2960 /* Create a new timeout */
2962 priv->updating_banner_timeout =
2963 g_timeout_add (2000, show_updating_banner, user_data);
2965 /* Remove the banner if exists */
2966 if (priv->updating_banner) {
2967 gtk_widget_destroy (priv->updating_banner);
2968 priv->updating_banner = NULL;
2974 modest_main_window_screen_is_on (ModestMainWindow *self)
2976 ModestMainWindowPrivate *priv = NULL;
2978 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2980 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2982 return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2986 remove_banners (ModestMainWindow *window)
2988 ModestMainWindowPrivate *priv;
2990 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2992 if (priv->retrieving_banner_timeout > 0) {
2993 g_source_remove (priv->retrieving_banner_timeout);
2994 priv->retrieving_banner_timeout = 0;
2997 if (priv->retrieving_banner != NULL) {
2998 gtk_widget_destroy (priv->retrieving_banner);
2999 priv->retrieving_banner = NULL;
3002 if (priv->updating_banner_timeout > 0) {
3003 g_source_remove (priv->updating_banner_timeout);
3004 priv->updating_banner_timeout = 0;
3007 if (priv->updating_banner != NULL) {
3008 gtk_widget_destroy (priv->updating_banner);
3009 priv->updating_banner = NULL;
3015 on_window_hide (GObject *gobject,
3019 g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
3021 if (!GTK_WIDGET_VISIBLE (gobject)) {
3022 TnyFolderStore *folder_store;
3023 ModestMainWindowPrivate *priv;
3025 /* Remove the currently shown banners */
3026 remove_banners (MODEST_MAIN_WINDOW (gobject));
3028 /* Force the folder view to sync the currently selected folder
3029 to save the read/unread status and to expunge messages */
3030 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
3031 folder_store = modest_folder_view_get_selected (priv->folder_view);
3032 if (TNY_IS_FOLDER (folder_store)) {
3033 ModestMailOperation *mail_op;
3035 mail_op = modest_mail_operation_new (NULL);
3036 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3038 modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
3039 g_object_unref (mail_op);
3040 g_object_unref (folder_store);
3046 on_window_destroy (GtkObject *widget,
3049 g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
3051 remove_banners (MODEST_MAIN_WINDOW (widget));
3055 retrieving_banner_destroyed (gpointer data,
3056 GObject *where_the_object_was)
3058 ModestMainWindowPrivate *priv = NULL;
3060 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
3062 priv->retrieving_banner = NULL;
3066 show_retrieving_banner (gpointer user_data)
3068 ModestMainWindowPrivate *priv = NULL;
3070 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
3072 if (priv->retrieving_banner == NULL) {
3074 /* We're outside the main lock */
3075 gdk_threads_enter ();
3076 priv->retrieving_banner =
3077 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
3078 _("mcen_ib_getting_items"));
3080 /* We need this because banners in Maemo could be
3081 destroyed by dialogs so we need to properly update
3082 our reference to it */
3083 g_object_weak_ref (G_OBJECT (priv->retrieving_banner),
3084 retrieving_banner_destroyed,
3086 gdk_threads_leave ();
3089 /* Remove timeout */
3090 priv->retrieving_banner_timeout = 0;