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-widget.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 #ifdef MODEST_HAVE_HILDON0_WIDGETS
70 #include <hildon-widgets/hildon-program.h>
72 #include <hildon/hildon-program.h>
73 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
75 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
82 /* 'private'/'protected' functions */
83 static void modest_main_window_class_init (ModestMainWindowClass *klass);
84 static void modest_main_window_init (ModestMainWindow *obj);
85 static void modest_main_window_finalize (GObject *obj);
87 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
88 GdkEventWindowState *event,
91 static void connect_signals (ModestMainWindow *self);
93 static void modest_main_window_disconnect_signals (ModestWindow *self);
95 static void restore_settings (ModestMainWindow *self,
96 gboolean do_folder_view_too);
98 static void save_state (ModestWindow *self);
100 static void update_menus (ModestMainWindow* self);
102 static void modest_main_window_show_toolbar (ModestWindow *window,
103 gboolean show_toolbar);
105 static void cancel_progressbar (GtkToolButton *toolbutton,
106 ModestMainWindow *self);
108 static void on_queue_changed (ModestMailOperationQueue *queue,
109 ModestMailOperation *mail_op,
110 ModestMailOperationQueueNotification type,
111 ModestMainWindow *self);
113 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
116 on_account_inserted (TnyAccountStore *accoust_store,
121 on_account_removed (TnyAccountStore *accoust_store,
125 static void on_default_account_changed (ModestAccountMgr* mgr,
128 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
132 static void on_configuration_key_changed (ModestConf* conf,
134 ModestConfEvent event,
135 ModestConfNotificationId id,
136 ModestMainWindow *self);
138 static void set_toolbar_mode (ModestMainWindow *self,
139 ModestToolBarModes mode);
141 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
143 static void on_show_account_action_toggled (GtkToggleAction *action,
146 static void on_refresh_account_action_activated (GtkAction *action,
149 static void on_account_updated (ModestAccountMgr* mgr, gchar* account_name,
152 static void on_send_receive_csm_activated (GtkMenuItem *item,
155 static void on_msg_count_changed (ModestHeaderView *header_view,
157 TnyFolderChange *change,
158 ModestMainWindow *main_window);
160 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
163 static GtkWidget * create_empty_view (void);
165 static gboolean on_folder_view_focus_in (GtkWidget *widget,
166 GdkEventFocus *event,
169 static gboolean on_header_view_focus_in (GtkWidget *widget,
170 GdkEventFocus *event,
173 static void on_folder_selection_changed (ModestFolderView *folder_view,
174 TnyFolderStore *folder_store,
176 ModestMainWindow *main_window);
178 static void set_at_least_one_account_visible(ModestMainWindow *self);
180 static void on_updating_msg_list (ModestHeaderView *header_view,
184 static gboolean restore_paned_timeout_handler (gpointer *data);
186 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
187 struct _ModestMainWindowPrivate {
188 GtkWidget *msg_paned;
189 GtkWidget *main_paned;
190 GtkWidget *main_vbox;
191 GtkWidget *contents_widget;
192 GtkWidget *empty_view;
194 /* Progress observers */
195 GtkWidget *progress_bar;
196 GSList *progress_widgets;
199 GtkWidget *progress_toolitem;
200 GtkWidget *cancel_toolitem;
201 GtkWidget *sort_toolitem;
202 GtkWidget *refresh_toolitem;
203 ModestToolBarModes current_toolbar_mode;
205 /* Merge ids used to add/remove accounts to the ViewMenu*/
206 GByteArray *merge_ids;
207 GtkActionGroup *view_additions_group;
209 /* On-demand widgets */
210 GtkWidget *accounts_popup;
211 GtkWidget *details_widget;
213 /* Optimized view enabled */
214 gboolean optimized_view;
216 /* Optimized view enabled */
217 gboolean send_receive_in_progress;
219 ModestHeaderView *header_view;
220 ModestFolderView *folder_view;
222 ModestMainWindowStyle style;
223 ModestMainWindowContentsStyle contents_style;
225 guint progress_bar_timeout;
226 guint restore_paned_timeout;
228 /* Signal handler UIDs */
229 GList *queue_err_signals;
232 /* "Updating" banner for header view */
233 GtkWidget *updating_banner;
234 guint updating_banner_timeout;
236 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
237 MODEST_TYPE_MAIN_WINDOW, \
238 ModestMainWindowPrivate))
240 typedef struct _GetMsgAsyncHelper {
241 ModestMainWindowPrivate *main_window_private;
243 ModestTnyMsgReplyType reply_type;
244 ModestTnyMsgForwardType forward_type;
251 static GtkWindowClass *parent_class = NULL;
254 /* Private actions */
255 /* This is the context sensitive menu: */
256 static const GtkActionEntry modest_folder_view_action_entries [] = {
258 /* Folder View CSM actions */
259 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
260 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
261 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
262 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
263 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
264 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
267 static const GtkActionEntry modest_header_view_action_entries [] = {
269 /* Header View CSM actions */
270 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
271 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
272 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
273 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
274 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
275 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
276 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
277 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
278 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
279 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
282 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
283 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
286 /************************************************************************/
289 modest_main_window_get_type (void)
291 static GType my_type = 0;
293 static const GTypeInfo my_info = {
294 sizeof(ModestMainWindowClass),
295 NULL, /* base init */
296 NULL, /* base finalize */
297 (GClassInitFunc) modest_main_window_class_init,
298 NULL, /* class finalize */
299 NULL, /* class data */
300 sizeof(ModestMainWindow),
302 (GInstanceInitFunc) modest_main_window_init,
305 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
313 modest_main_window_class_init (ModestMainWindowClass *klass)
315 GObjectClass *gobject_class;
316 gobject_class = (GObjectClass*) klass;
317 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
319 parent_class = g_type_class_peek_parent (klass);
320 gobject_class->finalize = modest_main_window_finalize;
322 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
324 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
325 modest_window_class->save_state_func = save_state;
326 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
327 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
328 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
332 modest_main_window_init (ModestMainWindow *obj)
334 ModestMainWindowPrivate *priv;
336 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
338 priv->queue_err_signals = NULL;
339 priv->msg_paned = NULL;
340 priv->main_paned = NULL;
341 priv->main_vbox = NULL;
342 priv->header_view = NULL;
343 priv->folder_view = NULL;
344 priv->contents_widget = NULL;
345 priv->accounts_popup = NULL;
346 priv->details_widget = NULL;
347 priv->empty_view = NULL;
348 priv->progress_widgets = NULL;
349 priv->progress_bar = NULL;
350 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
351 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
352 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
353 priv->merge_ids = NULL;
354 priv->optimized_view = FALSE;
355 priv->send_receive_in_progress = FALSE;
356 priv->progress_bar_timeout = 0;
357 priv->restore_paned_timeout = 0;
358 priv->sighandlers = NULL;
359 priv->updating_banner = NULL;
360 priv->updating_banner_timeout = 0;
362 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
364 "applications_email_mainview");
368 modest_main_window_finalize (GObject *obj)
370 ModestMainWindowPrivate *priv;
372 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
374 /* Sanity check: shouldn't be needed, the window mgr should
375 call this function before */
376 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
378 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
380 g_slist_free (priv->progress_widgets);
382 g_byte_array_free (priv->merge_ids, TRUE);
384 if (priv->progress_bar_timeout > 0) {
385 g_source_remove (priv->progress_bar_timeout);
386 priv->progress_bar_timeout = 0;
389 if (priv->updating_banner_timeout > 0) {
390 g_source_remove (priv->updating_banner_timeout);
391 priv->updating_banner_timeout = 0;
394 if (priv->updating_banner) {
395 gtk_widget_destroy (priv->updating_banner);
396 priv->updating_banner = NULL;
399 if (priv->restore_paned_timeout > 0) {
400 g_source_remove (priv->restore_paned_timeout);
401 priv->restore_paned_timeout = 0;
404 G_OBJECT_CLASS(parent_class)->finalize (obj);
408 modest_main_window_get_child_widget (ModestMainWindow *self,
409 ModestMainWindowWidgetType widget_type)
411 ModestMainWindowPrivate *priv;
414 g_return_val_if_fail (self, NULL);
415 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
418 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
420 switch (widget_type) {
421 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
422 widget = (GtkWidget*)priv->header_view; break;
423 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
424 widget = (GtkWidget*)priv->folder_view; break;
429 return widget ? GTK_WIDGET(widget) : NULL;
433 restore_paned_timeout_handler (gpointer *data)
435 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
436 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
439 /* Timeouts are outside the main lock */
440 gdk_threads_enter ();
441 if (GTK_WIDGET_VISIBLE (main_window)) {
442 conf = modest_runtime_get_conf ();
443 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
444 MODEST_CONF_MAIN_PANED_KEY);
446 gdk_threads_leave ();
453 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
456 ModestMainWindowPrivate *priv;
458 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
460 conf = modest_runtime_get_conf ();
462 modest_widget_memory_restore (conf, G_OBJECT(self),
463 MODEST_CONF_MAIN_WINDOW_KEY);
465 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
466 MODEST_CONF_HEADER_VIEW_KEY);
468 if (do_folder_view_too)
469 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
470 MODEST_CONF_FOLDER_VIEW_KEY);
472 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
473 MODEST_CONF_MAIN_PANED_KEY);
475 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
477 /* We need to force a redraw here in order to get the right
478 position of the horizontal paned separator */
479 gtk_widget_show (GTK_WIDGET (self));
484 save_state (ModestWindow *window)
487 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
488 ModestMainWindowPrivate *priv;
490 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
491 conf = modest_runtime_get_conf ();
493 modest_widget_memory_save (conf,G_OBJECT(self),
494 MODEST_CONF_MAIN_WINDOW_KEY);
495 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
496 MODEST_CONF_MAIN_PANED_KEY);
497 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
498 // MODEST_CONF_HEADER_VIEW_KEY);
499 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
500 MODEST_CONF_FOLDER_VIEW_KEY);
504 compare_display_names (ModestAccountSettings *a,
505 ModestAccountSettings *b)
507 return strcmp (modest_account_settings_get_display_name (a),
508 modest_account_settings_get_display_name (b));
512 update_menus (ModestMainWindow* self)
514 GSList *account_names, *iter, *accounts;
515 ModestMainWindowPrivate *priv;
516 ModestWindowPrivate *parent_priv;
517 ModestAccountMgr *mgr;
518 gint i, num_accounts;
520 gchar *default_account;
521 const gchar *active_account_name;
522 GtkWidget *send_receive_button, *item;
523 GtkAction *send_receive_all = NULL;
526 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
527 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
529 /* Get enabled account IDs */
530 mgr = modest_runtime_get_account_mgr ();
531 account_names = modest_account_mgr_account_names (mgr, TRUE);
532 iter = account_names;
536 ModestAccountSettings *settings =
537 modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
538 accounts = g_slist_prepend (accounts, settings);
542 modest_account_mgr_free_account_names (account_names);
543 account_names = NULL;
545 /* Order the list of accounts by its display name */
546 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
547 num_accounts = g_slist_length (accounts);
549 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
550 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
551 gtk_action_set_visible (send_receive_all, num_accounts > 0);
553 /* Delete old send&receive popup items. We can not just do a
554 menu_detach because it does not work well with
556 if (priv->accounts_popup)
557 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
558 (GtkCallback) gtk_widget_destroy, NULL);
560 /* Delete old entries in the View menu. Do not free groups, it
562 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
564 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
565 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
566 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
567 GTK_ACTION_GROUP (groups->data));
570 if (priv->merge_ids) {
571 for (i = 0; i < priv->merge_ids->len; i++)
572 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
573 g_byte_array_free (priv->merge_ids, TRUE);
575 /* We need to call this in order to ensure
576 that the new actions are added in the right
577 order (alphabetical) */
578 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
580 groups = g_list_next (groups);
582 priv->merge_ids = g_byte_array_sized_new (num_accounts);
584 /* Get send receive button */
585 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
586 "/ToolBar/ToolbarSendReceive");
588 /* Create the menu */
589 if (num_accounts > 1) {
590 if (!priv->accounts_popup)
591 priv->accounts_popup = gtk_menu_new ();
592 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
593 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
594 g_signal_connect (G_OBJECT (item),
596 G_CALLBACK (on_send_receive_csm_activated),
598 item = gtk_separator_menu_item_new ();
599 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
602 /* Create a new action group */
603 default_account = modest_account_mgr_get_default_account (mgr);
604 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
606 if (!active_account_name)
607 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
609 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
611 for (i = 0; i < num_accounts; i++) {
612 gchar *display_name = NULL;
613 const gchar *account_name;
614 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
617 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
620 account_name = modest_account_settings_get_account_name (settings);
622 if (default_account && account_name &&
623 !(strcmp (default_account, account_name) == 0)) {
624 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
625 modest_account_settings_get_display_name (settings));
627 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
628 modest_account_settings_get_display_name (settings));
631 /* Create action and add it to the action group. The
632 action name must be the account name, this way we
633 could know in the handlers the account to show */
634 if (settings && account_name) {
635 gchar* item_name, *refresh_action_name;
637 GtkAction *view_account_action, *refresh_account_action;
639 view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
640 display_name, NULL, NULL, 0));
641 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
642 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
643 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
645 if (active_account_name) {
646 if (active_account_name && account_name &&
647 (strcmp (active_account_name, account_name) == 0)) {
648 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
652 /* Add ui from account data. We allow 2^9-1 account
653 changes in a single execution because we're
654 downcasting the guint to a guint8 in order to use a
655 GByteArray. It should be enough. */
656 item_name = g_strconcat (account_name, "Menu", NULL);
657 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
658 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
659 gtk_ui_manager_add_ui (parent_priv->ui_manager,
661 "/MenuBar/ViewMenu/ViewMenuAdditions",
664 GTK_UI_MANAGER_MENUITEM,
667 /* Connect the action signal "activate" */
668 g_signal_connect_after (G_OBJECT (view_account_action),
670 G_CALLBACK (on_show_account_action_toggled),
673 /* Create the items for the Tools->Send&Receive submenu */
674 refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
675 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
676 display_name, NULL, NULL);
677 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
679 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
680 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
681 gtk_ui_manager_add_ui (parent_priv->ui_manager,
683 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
686 GTK_UI_MANAGER_MENUITEM,
688 g_free (refresh_action_name);
690 g_signal_connect_data (G_OBJECT (refresh_account_action),
692 G_CALLBACK (on_refresh_account_action_activated),
693 g_strdup (account_name),
694 (GClosureNotify) g_free,
697 /* Create item and add it to the send&receive
698 CSM. If there is only one account then
700 if (priv->accounts_popup) {
701 GtkWidget *label = gtk_label_new(NULL);
702 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
703 if (default_account && (strcmp(account_name, default_account) == 0))
705 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
706 gtk_label_set_markup (GTK_LABEL (label), escaped);
711 gtk_label_set_text (GTK_LABEL (label), display_name);
714 item = gtk_menu_item_new ();
715 gtk_container_add (GTK_CONTAINER (item), label);
717 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
718 g_signal_connect_data (G_OBJECT (item),
720 G_CALLBACK (on_send_receive_csm_activated),
721 g_strdup (account_name),
722 (GClosureNotify) g_free,
729 g_free (display_name);
732 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
734 /* We cannot do this in the loop above because this relies on the action
735 * group being inserted. This makes the default account appear in bold.
736 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
737 for (i = 0; i < num_accounts; i++) {
738 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
739 const gchar *account_name;
741 account_name = modest_account_settings_get_account_name (settings);
743 if(account_name && default_account &&
744 strcmp (account_name, default_account) == 0) {
745 gchar *item_name = g_strconcat (account_name, "Menu", NULL);
747 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
748 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
752 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
753 if (GTK_IS_LABEL (child)) {
754 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
755 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
756 gtk_label_set_markup (GTK_LABEL (child), bold_name);
761 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
762 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
766 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
767 if (GTK_IS_LABEL (child)) {
768 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
769 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
770 gtk_label_set_markup (GTK_LABEL (child), bold_name);
778 g_object_unref (settings);
781 if (priv->accounts_popup) {
782 /* Mandatory in order to view the menu contents */
783 gtk_widget_show_all (priv->accounts_popup);
785 /* Setup tap_and_hold just if was not done before*/
786 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
787 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
791 g_slist_free (accounts);
792 g_free (default_account);
795 /* Make sure that at least one account is viewed if there are any
796 * accounts, for instance when adding the first account: */
797 set_at_least_one_account_visible (self);
801 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
803 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
804 gtk_scrolled_window_add_with_viewport
805 (GTK_SCROLLED_WINDOW(win), widget);
807 gtk_container_add (GTK_CONTAINER(win),
818 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
820 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
822 GList *oerrsignals = priv->queue_err_signals;
823 while (oerrsignals) {
824 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
825 g_signal_handler_disconnect (esignal->queue, esignal->signal);
826 g_slice_free (QueueErrorSignal, esignal);
827 oerrsignals = g_list_next (oerrsignals);
829 g_list_free (priv->queue_err_signals);
830 priv->queue_err_signals = NULL;
835 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
837 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
840 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
844 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
846 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
848 /* Update visibility */
851 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
855 modest_main_window_disconnect_signals (ModestWindow *self)
857 ModestMainWindowPrivate *priv;
858 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
860 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
861 priv->sighandlers = NULL;
865 connect_signals (ModestMainWindow *self)
867 ModestWindowPrivate *parent_priv;
868 ModestMainWindowPrivate *priv;
871 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
872 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
877 modest_signal_mgr_connect (priv->sighandlers,
878 G_OBJECT(priv->folder_view), "key-press-event",
879 G_CALLBACK(on_inner_widgets_key_pressed), self);
881 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
882 "folder_selection_changed",
883 G_CALLBACK (on_folder_selection_changed),
886 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
887 "folder-display-name-changed",
888 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
891 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
893 G_CALLBACK (on_folder_view_focus_in),
896 /* Folder view CSM */
897 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
898 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
899 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
900 G_CALLBACK(_folder_view_csm_menu_activated),
904 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
905 G_CALLBACK(modest_ui_actions_on_header_selected), self);
907 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
908 G_CALLBACK(modest_ui_actions_on_header_activated), self);
910 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
911 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
913 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
914 G_CALLBACK(on_inner_widgets_key_pressed), self);
916 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
917 G_CALLBACK(on_msg_count_changed), self);
919 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
920 G_CALLBACK (on_header_view_focus_in), self);
922 modest_signal_mgr_connect (priv->sighandlers,
923 G_OBJECT (priv->header_view),
925 G_CALLBACK (on_updating_msg_list),
928 /* Header view CSM */
929 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
930 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
932 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
933 G_CALLBACK(_header_view_csm_menu_activated),
938 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
939 G_CALLBACK (modest_main_window_window_state_event),
942 /* Mail Operation Queue */
944 modest_signal_mgr_connect (priv->sighandlers,
945 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
947 G_CALLBACK (on_queue_changed), self);
949 /* Track changes in the device name */
951 modest_signal_mgr_connect (priv->sighandlers,
952 G_OBJECT(modest_runtime_get_conf ()),
954 G_CALLBACK (on_configuration_key_changed),
957 /* Track account changes. We need to refresh the toolbar */
959 modest_signal_mgr_connect (priv->sighandlers,
960 G_OBJECT (modest_runtime_get_account_store ()),
962 G_CALLBACK (on_account_inserted),
965 modest_signal_mgr_connect (priv->sighandlers,
966 G_OBJECT (modest_runtime_get_account_store ()),
968 G_CALLBACK (on_account_removed),
971 /* We need to refresh the send & receive menu to change the bold
972 * account when the default account changes. */
974 modest_signal_mgr_connect (priv->sighandlers,
975 G_OBJECT (modest_runtime_get_account_mgr ()),
976 "default_account_changed",
977 G_CALLBACK (on_default_account_changed),
981 modest_signal_mgr_connect (priv->sighandlers,
982 G_OBJECT (modest_runtime_get_account_mgr ()),
984 G_CALLBACK (on_account_updated),
988 modest_signal_mgr_connect (priv->sighandlers,
989 G_OBJECT (modest_runtime_get_account_store()),
990 "password_requested",
991 G_CALLBACK (modest_ui_actions_on_password_requested),
996 /** Idle handler, to send/receive at startup .*/
998 sync_accounts_cb (ModestMainWindow *win)
1000 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
1001 return FALSE; /* Do not call this idle handler again. */
1006 on_hildon_program_is_topmost_notify(GObject *self,
1007 GParamSpec *propert_param, gpointer user_data)
1009 HildonProgram *app = HILDON_PROGRAM (self);
1012 ModestWindow* self = MODEST_WINDOW(user_data);
1015 /* Note that use of hildon_program_set_can_hibernate()
1016 * is generally referred to as "setting the killable flag",
1017 * though hibernation does not seem equal to death.
1020 if (hildon_program_get_is_topmost (app)) {
1021 /* Prevent hibernation when the progam comes to the foreground,
1022 * because hibernation should only happen when the application
1023 * is in the background: */
1024 hildon_program_set_can_hibernate (app, FALSE);
1026 /* Allow hibernation if the program has gone to the background: */
1028 /* However, prevent hibernation while the settings are being changed: */
1029 const gboolean hibernation_prevented =
1030 modest_window_mgr_get_hibernation_is_prevented (
1031 modest_runtime_get_window_mgr ());
1033 if (hibernation_prevented)
1034 hildon_program_set_can_hibernate (app, FALSE);
1036 /* Allow hibernation, after saving the state: */
1037 modest_osso_save_state();
1038 hildon_program_set_can_hibernate (app, TRUE);
1045 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1047 GtkWidget *folder_win = (GtkWidget *) user_data;
1048 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1050 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1051 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1053 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1055 /* Connect signals */
1056 connect_signals (MODEST_MAIN_WINDOW (self));
1058 /* Set account store */
1059 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1060 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1062 /* Load previous osso state, for instance if we are being restored from
1064 modest_osso_load_state ();
1066 /* Restore window & widget settings */
1067 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1069 /* Check if accounts exist and show the account wizard if not */
1070 gboolean accounts_exist =
1071 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1073 if (!accounts_exist) {
1074 /* This is necessary to have the main window shown behind the dialog
1075 It's an ugly hack... jschmid */
1076 gtk_widget_show_all(GTK_WIDGET(self));
1077 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1080 GtkAction *send_receive_all;
1081 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1082 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1083 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1084 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1085 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 0);
1086 modest_account_mgr_free_account_names (accounts);
1087 update_menus (MODEST_MAIN_WINDOW (self));
1092 modest_main_window_new (void)
1094 ModestMainWindow *self = NULL;
1095 ModestMainWindowPrivate *priv = NULL;
1096 ModestWindowPrivate *parent_priv = NULL;
1097 GtkWidget *folder_win = NULL;
1098 ModestDimmingRulesGroup *menu_rules_group = NULL;
1099 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1100 GtkActionGroup *action_group = NULL;
1101 GError *error = NULL;
1102 ModestConf *conf = NULL;
1103 GtkAction *action = NULL;
1104 GdkPixbuf *window_icon;
1106 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1107 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1108 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1110 parent_priv->ui_manager = gtk_ui_manager_new();
1111 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1113 action_group = gtk_action_group_new ("ModestMainWindowActions");
1114 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1116 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1117 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1119 /* Add common actions */
1120 gtk_action_group_add_actions (action_group,
1121 modest_action_entries,
1122 G_N_ELEMENTS (modest_action_entries),
1125 gtk_action_group_add_actions (action_group,
1126 modest_folder_view_action_entries,
1127 G_N_ELEMENTS (modest_folder_view_action_entries),
1130 gtk_action_group_add_actions (action_group,
1131 modest_header_view_action_entries,
1132 G_N_ELEMENTS (modest_header_view_action_entries),
1135 gtk_action_group_add_toggle_actions (action_group,
1136 modest_toggle_action_entries,
1137 G_N_ELEMENTS (modest_toggle_action_entries),
1140 gtk_action_group_add_toggle_actions (action_group,
1141 modest_main_window_toggle_action_entries,
1142 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1145 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1146 g_object_unref (action_group);
1148 /* Load the UI definition */
1149 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1150 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1151 if (error != NULL) {
1152 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1153 g_error_free (error);
1157 /* Add common dimming rules */
1158 modest_dimming_rules_group_add_rules (menu_rules_group,
1159 modest_main_window_menu_dimming_entries,
1160 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1161 MODEST_WINDOW (self));
1162 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1163 modest_main_window_toolbar_dimming_entries,
1164 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1165 MODEST_WINDOW (self));
1167 /* Insert dimming rules group for this window */
1168 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1169 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1170 g_object_unref (menu_rules_group);
1171 g_object_unref (toolbar_rules_group);
1173 /* Add accelerators */
1174 gtk_window_add_accel_group (GTK_WINDOW (self),
1175 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1177 /* Menubar. Update the state of some toggles */
1178 parent_priv->menubar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/MenuBar");
1179 conf = modest_runtime_get_conf ();
1180 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1181 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1182 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1183 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1184 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1185 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1186 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1187 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1188 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1189 gtk_widget_show (parent_priv->menubar);
1191 /* Get device name */
1192 modest_maemo_utils_get_device_name ();
1196 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1197 if (!priv->header_view)
1198 g_printerr ("modest: cannot instantiate header view\n");
1199 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1200 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1201 MODEST_CONF_HEADER_VIEW_KEY);
1203 /* Other style properties of header view */
1204 g_object_set (G_OBJECT (priv->header_view),
1205 "rules-hint", FALSE,
1207 /* gtk_widget_show (priv->header_view); */
1210 priv->empty_view = create_empty_view ();
1211 gtk_widget_show (priv->empty_view);
1213 /* Create scrolled windows */
1214 folder_win = gtk_scrolled_window_new (NULL, NULL);
1215 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1216 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1218 GTK_POLICY_AUTOMATIC);
1219 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1221 GTK_POLICY_AUTOMATIC);
1222 /* gtk_widget_show (priv->contents_widget); */
1225 priv->main_paned = gtk_hpaned_new ();
1226 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1227 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1228 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1230 /* putting it all together... */
1231 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1232 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1233 gtk_widget_show (priv->main_vbox);
1235 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1237 HildonProgram *app = hildon_program_get_instance ();
1238 hildon_program_add_window (app, HILDON_WINDOW (self));
1240 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1241 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1243 g_signal_connect (G_OBJECT(self), "show",
1244 G_CALLBACK (modest_main_window_on_show), folder_win);
1246 /* Set window icon */
1247 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1249 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1250 g_object_unref (window_icon);
1253 /* Dont't restore settings here,
1254 * because it requires a gtk_widget_show(),
1255 * and we don't want to do that until later,
1256 * so that the UI is not visible for non-menu D-Bus activation.
1258 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1260 return MODEST_WINDOW(self);
1264 modest_main_window_set_style (ModestMainWindow *self,
1265 ModestMainWindowStyle style)
1267 ModestMainWindowPrivate *priv;
1268 ModestWindowPrivate *parent_priv;
1272 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1274 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1275 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1277 /* no change -> nothing to do */
1278 if (priv->style == style)
1281 /* Get toggle button and update the state if needed. This will
1282 happen only when the set_style is not invoked from the UI,
1283 for example when it's called from widget memory */
1284 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1285 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1286 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1287 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1288 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1289 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1290 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1293 priv->style = style;
1295 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1296 /* Remove main paned */
1297 g_object_ref (priv->main_paned);
1298 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1300 /* Reparent the contents widget to the main vbox */
1301 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1304 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1305 /* Remove header view */
1306 g_object_ref (priv->contents_widget);
1307 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1309 /* Reparent the main paned */
1310 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1311 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1315 g_return_if_reached ();
1318 /* Let header view grab the focus if it's being shown */
1319 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1320 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1322 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1325 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1328 ModestMainWindowStyle
1329 modest_main_window_get_style (ModestMainWindow *self)
1331 ModestMainWindowPrivate *priv;
1333 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1335 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1342 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1344 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1345 ModestWindowPrivate *parent_priv;
1346 ModestWindowMgr *mgr;
1347 gboolean is_fullscreen;
1348 GtkAction *fs_toggle_action;
1351 mgr = modest_runtime_get_window_mgr ();
1353 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1355 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1357 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1358 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1359 if (is_fullscreen != active) {
1360 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1369 set_homogeneous (GtkWidget *widget,
1372 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1373 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1377 modest_main_window_show_toolbar (ModestWindow *self,
1378 gboolean show_toolbar)
1380 ModestMainWindowPrivate *priv = NULL;
1381 ModestWindowPrivate *parent_priv = NULL;
1382 GtkWidget *reply_button = NULL, *menu = NULL;
1383 GtkWidget *placeholder = NULL;
1385 const gchar *action_name;
1388 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1389 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1390 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1392 /* Set optimized view status */
1393 priv->optimized_view = !show_toolbar;
1395 if (!parent_priv->toolbar) {
1396 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1398 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1400 /* Set homogeneous toolbar */
1401 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1402 set_homogeneous, NULL);
1404 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1405 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1406 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1407 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1408 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1409 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1410 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1411 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1413 /* Add ProgressBar (Transfer toolbar) */
1414 priv->progress_bar = modest_progress_bar_widget_new ();
1415 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1416 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1417 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1418 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1419 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1421 /* Connect cancel 'clicked' signal to abort progress mode */
1422 g_signal_connect(priv->cancel_toolitem, "clicked",
1423 G_CALLBACK(cancel_progressbar),
1426 /* Add it to the observers list */
1427 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1430 hildon_window_add_toolbar (HILDON_WINDOW (self),
1431 GTK_TOOLBAR (parent_priv->toolbar));
1433 /* Set reply button tap and hold menu */
1434 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1435 "/ToolBar/ToolbarMessageReply");
1436 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1437 "/ToolbarReplyCSM");
1438 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1440 /* Set send & receive button tap and hold menu */
1441 update_menus (MODEST_MAIN_WINDOW (self));
1445 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1446 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1447 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1449 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1450 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1451 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1453 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1455 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1459 /* Update also the actions (to update the toggles in the
1460 menus), we have to do it manually because some other window
1461 of the same time could have changed it (remember that the
1462 toolbar fullscreen mode is shared by all the windows of the
1464 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1465 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1467 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1469 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1470 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1475 on_account_inserted (TnyAccountStore *accoust_store,
1476 TnyAccount *account,
1479 update_menus (MODEST_MAIN_WINDOW (user_data));
1483 on_default_account_changed (ModestAccountMgr* mgr,
1486 update_menus (MODEST_MAIN_WINDOW (user_data));
1490 on_account_removed (TnyAccountStore *accoust_store,
1491 TnyAccount *account,
1494 update_menus (MODEST_MAIN_WINDOW (user_data));
1498 on_account_updated (ModestAccountMgr* mgr,
1499 gchar* account_name,
1502 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1504 if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS) {
1505 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1510 * This function manages the key events used to navigate between
1511 * header and folder views (when the window is in split view)
1514 * -------------------------------------------------
1515 * HeaderView GDK_Left Move focus to folder view
1516 * FolderView GDK_Right Move focus to header view
1518 * There is no need to scroll to selected row, the widgets will be the
1519 * responsibles of doing that (probably managing the focus-in event
1522 on_inner_widgets_key_pressed (GtkWidget *widget,
1526 ModestMainWindowPrivate *priv;
1528 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1530 /* Do nothing if we're in SIMPLE style */
1531 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1534 if (MODEST_IS_HEADER_VIEW (widget)) {
1535 if (event->keyval == GDK_Left)
1536 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1537 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1538 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1539 if (selected_headers > 1) {
1540 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1544 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1545 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1551 set_alignment (GtkWidget *widget,
1554 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1555 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1559 create_empty_view (void)
1561 GtkLabel *label = NULL;
1562 GtkWidget *align = NULL;
1564 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1565 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1566 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1567 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1569 return GTK_WIDGET(align);
1573 * Free the returned string
1576 get_gray_color_markup (GtkWidget *styled_widget)
1578 gchar *gray_color_markup = NULL;
1579 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1580 /* Obtain the secondary text color. We need a realized widget, that's why
1581 we get styled_widget from outside */
1583 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1584 gray_color_markup = modest_text_utils_get_color_string (&color);
1585 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1587 if (!gray_color_markup)
1588 gray_color_markup = g_strdup ("#BBBBBB");
1590 return gray_color_markup;
1594 * Free the returned string
1597 create_device_name_visual_string (const gchar *device_name,
1598 const gchar *gray_color_markup)
1602 /* We have to use "" to fill the %s of the translation. We can
1603 not just use the device name because the device name is
1604 shown in a different color, so it could not be included
1605 into the <span> tag */
1606 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1607 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1617 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1619 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1624 gchar *gray_color_markup;
1626 vbox = gtk_vbox_new (FALSE, 0);
1628 gray_color_markup = get_gray_color_markup (styled_widget);
1630 /* Account description: */
1631 if (modest_tny_account_is_virtual_local_folders (account)
1632 || (modest_tny_account_is_memory_card_account (account))) {
1634 /* Get device name */
1635 gchar *device_name = NULL;
1636 if (modest_tny_account_is_virtual_local_folders (account))
1637 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1638 MODEST_CONF_DEVICE_NAME, NULL);
1640 device_name = g_strdup (tny_account_get_name (account));
1642 label = create_device_name_visual_string ((const gchar *) device_name,
1643 (const gchar *) gray_color_markup);
1644 label_w = gtk_label_new (NULL);
1645 gtk_label_set_markup (GTK_LABEL (label_w), label);
1646 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1647 g_free (device_name);
1650 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1651 gtk_box_pack_start (GTK_BOX (vbox),
1652 gtk_label_new (tny_account_get_name (account)),
1655 /* Other accounts, such as IMAP and POP: */
1660 /* Put proto in uppercase */
1661 proto = g_string_new (tny_account_get_proto (account));
1662 proto = g_string_ascii_up (proto);
1664 /* note: mcen_fi_localroot_description is something like "%s account"
1665 * however, we should display "%s account: %s"... therefore, ugly tmp */
1666 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1667 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1668 gray_color_markup, tmp, tny_account_get_name (account));
1671 label_w = gtk_label_new (NULL);
1672 gtk_label_set_markup (GTK_LABEL (label_w), label);
1673 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1674 g_string_free (proto, TRUE);
1680 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1681 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1682 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1683 modest_tny_folder_store_get_message_count (folder_store));
1684 label_w = gtk_label_new (NULL);
1685 gtk_label_set_markup (GTK_LABEL (label_w), label);
1686 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1690 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1692 _("mcen_fi_rootfolder_folders"),
1693 modest_tny_folder_store_get_folder_count (folder_store));
1694 label_w = gtk_label_new (NULL);
1695 gtk_label_set_markup (GTK_LABEL (label_w), label);
1696 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1700 if (modest_tny_account_is_virtual_local_folders (account)
1701 || modest_tny_account_is_memory_card_account (account)) {
1703 gchar *size = modest_text_utils_get_display_size (
1704 modest_tny_folder_store_get_local_size (folder_store));
1706 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1707 gray_color_markup, _("mcen_fi_rootfolder_size"),
1711 label_w = gtk_label_new (NULL);
1712 gtk_label_set_markup (GTK_LABEL (label_w), label);
1713 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1715 } else if (TNY_IS_ACCOUNT(folder_store)) {
1716 TnyAccount *account = TNY_ACCOUNT(folder_store);
1718 time_t last_updated;
1719 const gchar *last_updated_string;
1720 /* Get last updated from configuration */
1721 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1722 tny_account_get_id (account));
1724 if (last_updated > 0)
1725 last_updated_string = modest_text_utils_get_display_date(last_updated);
1727 last_updated_string = g_strdup (_("mcen_va_never"));
1729 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1730 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1731 label_w = gtk_label_new (NULL);
1732 gtk_label_set_markup (GTK_LABEL (label_w), label);
1733 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1737 g_free (gray_color_markup);
1740 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1746 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1748 ModestMainWindowPrivate *priv = NULL;
1750 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1752 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1754 return priv->send_receive_in_progress;
1758 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1760 GtkAction *action = NULL;
1761 GtkWidget *widget = NULL;
1762 ModestMainWindowPrivate *priv = NULL;
1764 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1765 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1767 priv->send_receive_in_progress = TRUE;
1769 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1770 gtk_action_set_sensitive (action, FALSE);
1771 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1772 /* gtk_action_set_sensitive (action, FALSE); */
1773 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1774 gtk_widget_set_sensitive (widget, FALSE);
1778 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1780 GtkAction *action = NULL;
1781 GtkWidget *widget = NULL;
1782 ModestMainWindowPrivate *priv = NULL;
1784 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1785 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1787 priv->send_receive_in_progress = FALSE;
1789 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1790 gtk_action_set_sensitive (action, TRUE);
1791 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1792 /* gtk_action_set_sensitive (action, TRUE); */
1793 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1794 gtk_widget_set_sensitive (widget, TRUE);
1799 on_msg_count_changed (ModestHeaderView *header_view,
1801 TnyFolderChange *change,
1802 ModestMainWindow *main_window)
1804 gboolean folder_empty = FALSE;
1805 gboolean all_marked_as_deleted = FALSE;
1806 TnyFolderChangeChanged changed;
1807 ModestMainWindowPrivate *priv;
1809 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1810 g_return_if_fail (TNY_IS_FOLDER(folder));
1811 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1812 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1814 changed = tny_folder_change_get_changed (change);
1816 /* If something changes */
1817 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1818 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1820 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1822 /* Check header removed (hide marked as DELETED headers) */
1823 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1824 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1827 /* Check if all messages are marked to be deleted */
1828 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1829 folder_empty = folder_empty || all_marked_as_deleted ;
1831 /* Set contents style of headers view */
1833 modest_main_window_set_contents_style (main_window,
1834 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1835 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1838 modest_main_window_set_contents_style (main_window,
1839 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1845 modest_main_window_set_contents_style (ModestMainWindow *self,
1846 ModestMainWindowContentsStyle style)
1848 ModestMainWindowPrivate *priv;
1850 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1852 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1854 /* We allow to set the same content style than the previously
1855 set if there are details, because it could happen when we're
1856 selecting different accounts consecutively */
1857 if ((priv->contents_style == style) &&
1858 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1861 /* Remove previous child. Delete it if it was an account
1863 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1865 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1866 g_object_ref (content);
1867 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1868 g_object_ref (priv->empty_view);
1869 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1872 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1875 priv->contents_style = style;
1877 switch (priv->contents_style) {
1878 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1879 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1880 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1883 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1885 /* if we're started without main win, there may not be a folder
1886 * view. this fixes a GLib-Critical */
1887 if (priv->folder_view) {
1888 TnyFolderStore *selected_folderstore =
1889 modest_folder_view_get_selected (priv->folder_view);
1890 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1891 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1892 TNY_ACCOUNT (selected_folderstore));
1894 wrap_in_scrolled_window (priv->contents_widget,
1895 priv->details_widget);
1897 g_object_unref (selected_folderstore);
1898 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1903 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1904 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1905 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1909 g_return_if_reached ();
1913 gtk_widget_show_all (priv->contents_widget);
1916 ModestMainWindowContentsStyle
1917 modest_main_window_get_contents_style (ModestMainWindow *self)
1919 ModestMainWindowPrivate *priv;
1921 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1923 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1924 return priv->contents_style;
1929 on_configuration_key_changed (ModestConf* conf,
1931 ModestConfEvent event,
1932 ModestConfNotificationId id,
1933 ModestMainWindow *self)
1935 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1936 TnyAccount *account = NULL;
1938 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1941 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1944 if (priv->folder_view)
1945 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1947 if (account && TNY_IS_ACCOUNT (account) &&
1948 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1951 const gchar *device_name;
1952 gchar *new_text, *gray_color_markup;
1955 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1956 label = GTK_LABEL (children->data);
1958 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1959 MODEST_CONF_DEVICE_NAME, NULL);
1961 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1962 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1964 gtk_label_set_markup (label, new_text);
1965 gtk_widget_show (GTK_WIDGET (label));
1967 g_free (gray_color_markup);
1969 g_list_free (children);
1971 g_object_unref (account);
1975 set_toolbar_transfer_mode (ModestMainWindow *self)
1977 ModestMainWindowPrivate *priv = NULL;
1979 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1981 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1983 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1985 if (priv->progress_bar_timeout > 0) {
1986 g_source_remove (priv->progress_bar_timeout);
1987 priv->progress_bar_timeout = 0;
1994 set_toolbar_mode (ModestMainWindow *self,
1995 ModestToolBarModes mode)
1997 ModestWindowPrivate *parent_priv = NULL;
1998 ModestMainWindowPrivate *priv = NULL;
1999 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2001 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2003 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2004 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2006 /* In case this was called before the toolbar exists: */
2007 if (!(parent_priv->toolbar))
2010 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2012 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2013 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2014 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2016 /* Sets current toolbar mode */
2017 priv->current_toolbar_mode = mode;
2019 /* Checks the dimming rules */
2020 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2022 /* Show and hide toolbar items */
2024 case TOOLBAR_MODE_NORMAL:
2026 gtk_action_set_visible (sort_action, TRUE);
2028 gtk_action_set_visible (refresh_action, TRUE);
2029 if (priv->progress_toolitem) {
2030 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2031 gtk_widget_hide (priv->progress_toolitem);
2033 if (priv->progress_bar)
2034 gtk_widget_hide (priv->progress_bar);
2037 gtk_action_set_visible (cancel_action, FALSE);
2039 /* Hide toolbar if optimized view is enabled */
2040 if (priv->optimized_view)
2041 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2043 case TOOLBAR_MODE_TRANSFER:
2045 gtk_action_set_visible (sort_action, FALSE);
2047 gtk_action_set_visible (refresh_action, FALSE);
2049 gtk_action_set_visible (cancel_action, TRUE);
2050 if (priv->progress_bar)
2051 gtk_widget_show (priv->progress_bar);
2052 if (priv->progress_toolitem) {
2053 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2054 gtk_widget_show (priv->progress_toolitem);
2057 /* Show toolbar if it's hiden (optimized view ) */
2058 if (priv->optimized_view)
2059 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2062 g_return_if_reached ();
2067 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2069 ModestMainWindowPrivate *priv;
2071 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2072 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2074 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2078 cancel_progressbar (GtkToolButton *toolbutton,
2079 ModestMainWindow *self)
2082 ModestMainWindowPrivate *priv;
2084 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2086 /* Get operation observers and cancel all the operations */
2087 tmp = priv->progress_widgets;
2089 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2090 tmp=g_slist_next(tmp);
2095 observers_empty (ModestMainWindow *self)
2098 ModestMainWindowPrivate *priv;
2099 gboolean is_empty = TRUE;
2100 guint pending_ops = 0;
2102 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2103 tmp = priv->progress_widgets;
2105 /* Check all observers */
2106 while (tmp && is_empty) {
2107 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2108 is_empty = pending_ops == 0;
2110 tmp = g_slist_next(tmp);
2118 * Gets the toolbar mode needed for each mail operation. It stores in
2119 * @mode_changed if the toolbar mode has changed or not
2121 static ModestToolBarModes
2122 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2123 ModestMailOperation *mail_op,
2124 gboolean *mode_changed)
2126 ModestToolBarModes mode;
2127 ModestMainWindowPrivate *priv;
2129 *mode_changed = FALSE;
2130 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2132 /* Get toolbar mode from operation id*/
2133 switch (modest_mail_operation_get_type_operation (mail_op)) {
2134 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2135 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2136 mode = TOOLBAR_MODE_TRANSFER;
2137 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2138 *mode_changed = TRUE;
2141 mode = TOOLBAR_MODE_NORMAL;
2147 on_mail_operation_started (ModestMailOperation *mail_op,
2150 ModestMainWindow *self;
2151 ModestMailOperationTypeOperation op_type;
2152 ModestMainWindowPrivate *priv;
2153 ModestToolBarModes mode;
2155 gboolean mode_changed = FALSE;
2156 TnyAccount *account;
2158 self = MODEST_MAIN_WINDOW (user_data);
2159 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2161 /* Do not show progress for receiving operations if the
2162 account is the local account or the MMC one */
2163 op_type = modest_mail_operation_get_type_operation (mail_op);
2164 account = modest_mail_operation_get_account (mail_op);
2165 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2168 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2169 modest_tny_account_is_memory_card_account (account));
2170 g_object_unref (account);
2175 /* Get toolbar mode from operation id*/
2176 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2178 /* Add operation observers and change toolbar if neccessary*/
2179 tmp = priv->progress_widgets;
2180 if (mode == TOOLBAR_MODE_TRANSFER) {
2182 set_toolbar_transfer_mode(self);
2185 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2187 tmp = g_slist_next (tmp);
2193 on_mail_operation_finished (ModestMailOperation *mail_op,
2196 ModestToolBarModes mode;
2197 ModestMailOperationTypeOperation op_type;
2199 ModestMainWindow *self;
2200 gboolean mode_changed;
2201 TnyAccount *account;
2202 ModestMainWindowPrivate *priv;
2204 self = MODEST_MAIN_WINDOW (user_data);
2205 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2207 /* The mail operation was not added to the progress objects if
2208 the account was the local account or the MMC one */
2209 op_type = modest_mail_operation_get_type_operation (mail_op);
2210 account = modest_mail_operation_get_account (mail_op);
2211 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2214 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2215 modest_tny_account_is_memory_card_account (account));
2216 g_object_unref (account);
2221 /* Get toolbar mode from operation id*/
2222 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2224 /* Change toolbar mode */
2225 tmp = priv->progress_widgets;
2226 if (mode == TOOLBAR_MODE_TRANSFER) {
2228 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2230 tmp = g_slist_next (tmp);
2233 /* If no more operations are being observed, NORMAL mode is enabled again */
2234 if (observers_empty (self)) {
2235 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2241 on_queue_changed (ModestMailOperationQueue *queue,
2242 ModestMailOperation *mail_op,
2243 ModestMailOperationQueueNotification type,
2244 ModestMainWindow *self)
2246 ModestMainWindowPrivate *priv;
2248 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2250 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2251 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2253 "operation-started",
2254 G_CALLBACK (on_mail_operation_started),
2256 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2258 "operation-finished",
2259 G_CALLBACK (on_mail_operation_finished),
2261 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2262 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2264 "operation-started");
2265 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2267 "operation-finished");
2272 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2274 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2276 ModestAccountMgr *mgr;
2277 ModestAccountSettings *settings;
2278 ModestServerAccountSettings *store_settings = NULL;
2280 /* Get account data */
2281 mgr = modest_runtime_get_account_mgr ();
2282 settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2284 store_settings = modest_account_settings_get_store_settings (settings);
2286 /* Set the new visible & active account */
2287 if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) {
2288 const gchar *account_name;
2290 account_name = modest_account_settings_get_account_name (settings);
2292 modest_folder_view_set_account_id_of_visible_server_account
2294 modest_server_account_settings_get_account_name (store_settings));
2295 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2296 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2297 if (action != NULL) {
2298 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2299 modest_utils_toggle_action_set_active_block_notify (
2300 GTK_TOGGLE_ACTION (action),
2306 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2311 g_object_unref (store_settings);
2312 g_object_unref (settings);
2316 /* Make sure that at least one account is "viewed": */
2318 set_at_least_one_account_visible(ModestMainWindow *self)
2320 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2321 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2323 if (!(priv->folder_view)) {
2324 /* It is too early to do this. */
2328 const gchar *active_server_account_name =
2329 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2331 if (!active_server_account_name ||
2332 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2334 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2335 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2336 if (default_modest_name) {
2337 set_account_visible (self, default_modest_name);
2338 } else if (first_modest_name) {
2339 set_account_visible (self, first_modest_name);
2341 g_free (first_modest_name);
2342 g_free (default_modest_name);
2347 on_show_account_action_toggled (GtkToggleAction *action,
2350 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2352 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2353 if (gtk_toggle_action_get_active (action))
2354 set_account_visible (self, acc_name);
2358 refresh_account (const gchar *account_name)
2362 /* win must already exists here, obviously */
2363 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2366 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2370 /* If account_name == NULL, we must update all (option All) */
2372 modest_ui_actions_do_send_receive_all (win);
2374 modest_ui_actions_do_send_receive (account_name, win);
2379 on_refresh_account_action_activated (GtkAction *action,
2382 refresh_account ((const gchar*) user_data);
2386 on_send_receive_csm_activated (GtkMenuItem *item,
2389 refresh_account ((const gchar*) user_data);
2393 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2395 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2397 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2403 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2405 ModestMainWindow *main_window = NULL;
2407 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2408 main_window = MODEST_MAIN_WINDOW (userdata);
2410 /* Update toolbar dimming state */
2411 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2417 on_header_view_focus_in (GtkWidget *widget,
2418 GdkEventFocus *event,
2421 ModestMainWindow *main_window = NULL;
2423 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2425 main_window = MODEST_MAIN_WINDOW (userdata);
2427 /* Update toolbar dimming state */
2428 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2434 on_folder_selection_changed (ModestFolderView *folder_view,
2435 TnyFolderStore *folder_store,
2437 ModestMainWindow *main_window)
2439 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2440 GtkAction *action = NULL;
2441 gboolean show_reply = TRUE;
2442 gboolean show_forward = TRUE;
2443 gboolean show_cancel_send = FALSE;
2444 gboolean show_clipboard = TRUE;
2445 gboolean show_delete = TRUE;
2448 if (TNY_IS_ACCOUNT (folder_store)) {
2449 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2450 } else if (TNY_IS_FOLDER (folder_store)) {
2451 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2452 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2453 TNY_FOLDER (folder_store));
2454 switch (folder_type) {
2455 case TNY_FOLDER_TYPE_DRAFTS:
2456 show_clipboard = show_delete = TRUE;
2457 show_reply = show_forward = show_cancel_send = FALSE;
2459 case TNY_FOLDER_TYPE_SENT:
2460 show_forward = show_clipboard = show_delete = TRUE;
2461 show_reply = show_cancel_send = FALSE;
2463 case TNY_FOLDER_TYPE_OUTBOX:
2464 show_clipboard = show_delete = show_cancel_send = TRUE;
2465 show_reply = show_forward = FALSE;
2467 case TNY_FOLDER_TYPE_INVALID:
2468 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2471 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2472 show_cancel_send = FALSE;
2475 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2476 show_cancel_send = FALSE;
2481 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2482 gtk_action_set_visible (action, show_reply);
2483 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2484 gtk_action_set_visible (action, show_reply);
2485 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2486 gtk_action_set_visible (action, show_forward);
2487 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2488 gtk_action_set_visible (action, show_cancel_send);
2489 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2490 gtk_action_set_visible (action, show_delete);
2492 /* We finally call to the ui actions handler, after updating properly
2493 * the header view CSM */
2494 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2498 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2499 GtkTreeModel *model,
2500 GtkTreeRowReference *row_reference,
2501 ModestMainWindow *self)
2503 ModestMainWindowPrivate *priv = NULL;
2504 GtkTreeModel *header_model = NULL;
2505 GtkTreePath *path = NULL;
2507 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2508 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2509 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2511 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2512 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2514 /* Do nothing if we changed the folder in the main view */
2515 if (header_model != model)
2518 /* Select the message in the header view */
2519 path = gtk_tree_row_reference_get_path (row_reference);
2520 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2522 gtk_tree_path_free (path);
2528 show_updating_banner (gpointer user_data)
2530 ModestMainWindowPrivate *priv = NULL;
2532 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2534 if (priv->updating_banner == NULL) {
2536 /* We're outside the main lock */
2537 gdk_threads_enter ();
2538 priv->updating_banner =
2539 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2540 _CS ("ckdg_pb_updating"));
2541 gdk_threads_leave ();
2544 /* Remove timeout */
2545 priv->updating_banner_timeout = 0;
2550 * We use this function to show/hide a progress banner showing
2551 * "Updating" while the header view is being filled. We're not showing
2552 * it unless the update takes more than 2 seconds
2554 * If starting = TRUE then the refresh is starting, otherwise it means
2555 * that is has just finished
2558 on_updating_msg_list (ModestHeaderView *header_view,
2562 ModestMainWindowPrivate *priv = NULL;
2564 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2566 /* Remove old timeout */
2567 if (priv->updating_banner_timeout > 0) {
2568 g_source_remove (priv->updating_banner_timeout);
2569 priv->updating_banner_timeout = 0;
2572 /* Create a new timeout */
2574 priv->updating_banner_timeout =
2575 g_timeout_add (2000, show_updating_banner, user_data);
2577 /* Remove the banner if exists */
2578 if (priv->updating_banner) {
2579 gtk_widget_destroy (priv->updating_banner);
2580 priv->updating_banner = NULL;