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-maemo-utils.h>
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-mail-operation.h"
60 #include "modest-icon-names.h"
61 #include "modest-progress-bar-widget.h"
62 #include "modest-text-utils.h"
63 #include "modest-ui-dimming-manager.h"
64 #include "maemo/modest-osso-state-saving.h"
65 #include "modest-text-utils.h"
66 #include "modest-signal-mgr.h"
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-program.h>
71 #include <hildon/hildon-program.h>
72 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
74 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
81 /* 'private'/'protected' functions */
82 static void modest_main_window_class_init (ModestMainWindowClass *klass);
83 static void modest_main_window_init (ModestMainWindow *obj);
84 static void modest_main_window_finalize (GObject *obj);
86 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
87 GdkEventWindowState *event,
90 static void connect_signals (ModestMainWindow *self);
92 static void modest_main_window_disconnect_signals (ModestWindow *self);
94 static void restore_settings (ModestMainWindow *self,
95 gboolean do_folder_view_too);
97 static void save_state (ModestWindow *self);
99 static void update_menus (ModestMainWindow* self);
101 static void modest_main_window_show_toolbar (ModestWindow *window,
102 gboolean show_toolbar);
104 static void cancel_progressbar (GtkToolButton *toolbutton,
105 ModestMainWindow *self);
107 static void on_queue_changed (ModestMailOperationQueue *queue,
108 ModestMailOperation *mail_op,
109 ModestMailOperationQueueNotification type,
110 ModestMainWindow *self);
112 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
115 on_account_inserted (TnyAccountStore *accoust_store,
120 on_account_removed (TnyAccountStore *accoust_store,
124 static void on_default_account_changed (ModestAccountMgr* mgr,
127 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
131 static void on_configuration_key_changed (ModestConf* conf,
133 ModestConfEvent event,
134 ModestConfNotificationId id,
135 ModestMainWindow *self);
137 static void set_toolbar_mode (ModestMainWindow *self,
138 ModestToolBarModes mode);
140 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
142 static void on_show_account_action_toggled (GtkToggleAction *action,
145 static void on_refresh_account_action_activated (GtkAction *action,
148 static void on_send_receive_csm_activated (GtkMenuItem *item,
151 static void on_msg_count_changed (ModestHeaderView *header_view,
153 TnyFolderChange *change,
154 ModestMainWindow *main_window);
156 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
159 static GtkWidget * create_empty_view (void);
161 static gboolean on_folder_view_focus_in (GtkWidget *widget,
162 GdkEventFocus *event,
165 static gboolean on_header_view_focus_in (GtkWidget *widget,
166 GdkEventFocus *event,
169 static void modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
170 TnyFolderStore *folder_store,
172 ModestMainWindow *main_window);
174 static void set_at_least_one_account_visible(ModestMainWindow *self);
176 static void on_updating_msg_list (ModestHeaderView *header_view,
180 static gboolean restore_paned_timeout_handler (gpointer *data);
182 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
183 struct _ModestMainWindowPrivate {
184 GtkWidget *msg_paned;
185 GtkWidget *main_paned;
186 GtkWidget *main_vbox;
187 GtkWidget *contents_widget;
188 GtkWidget *empty_view;
190 /* Progress observers */
191 GtkWidget *progress_bar;
192 GSList *progress_widgets;
195 GtkWidget *progress_toolitem;
196 GtkWidget *cancel_toolitem;
197 GtkWidget *sort_toolitem;
198 GtkWidget *refresh_toolitem;
199 ModestToolBarModes current_toolbar_mode;
201 /* Merge ids used to add/remove accounts to the ViewMenu*/
202 GByteArray *merge_ids;
203 GtkActionGroup *view_additions_group;
205 /* On-demand widgets */
206 GtkWidget *accounts_popup;
207 GtkWidget *details_widget;
209 /* Optimized view enabled */
210 gboolean optimized_view;
212 /* Optimized view enabled */
213 gboolean send_receive_in_progress;
215 ModestHeaderView *header_view;
216 ModestFolderView *folder_view;
218 ModestMainWindowStyle style;
219 ModestMainWindowContentsStyle contents_style;
221 guint progress_bar_timeout;
222 guint restore_paned_timeout;
224 /* Signal handler UIDs */
225 GList *queue_err_signals;
228 /* "Updating" banner for header view */
229 GtkWidget *updating_banner;
230 guint updating_banner_timeout;
232 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
233 MODEST_TYPE_MAIN_WINDOW, \
234 ModestMainWindowPrivate))
236 typedef struct _GetMsgAsyncHelper {
237 ModestMainWindowPrivate *main_window_private;
239 ModestTnyMsgReplyType reply_type;
240 ModestTnyMsgForwardType forward_type;
247 static GtkWindowClass *parent_class = NULL;
250 /* Private actions */
251 /* This is the context sensitive menu: */
252 static const GtkActionEntry modest_folder_view_action_entries [] = {
254 /* Folder View CSM actions */
255 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
256 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
257 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
258 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
259 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
260 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
263 static const GtkActionEntry modest_header_view_action_entries [] = {
265 /* Header View CSM actions */
266 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
267 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
268 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
269 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
270 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
271 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
272 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
273 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
274 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
275 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
278 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
279 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
282 /************************************************************************/
285 modest_main_window_get_type (void)
287 static GType my_type = 0;
289 static const GTypeInfo my_info = {
290 sizeof(ModestMainWindowClass),
291 NULL, /* base init */
292 NULL, /* base finalize */
293 (GClassInitFunc) modest_main_window_class_init,
294 NULL, /* class finalize */
295 NULL, /* class data */
296 sizeof(ModestMainWindow),
298 (GInstanceInitFunc) modest_main_window_init,
301 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
309 modest_main_window_class_init (ModestMainWindowClass *klass)
311 GObjectClass *gobject_class;
312 gobject_class = (GObjectClass*) klass;
313 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
315 parent_class = g_type_class_peek_parent (klass);
316 gobject_class->finalize = modest_main_window_finalize;
318 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
320 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
321 modest_window_class->save_state_func = save_state;
322 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
323 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
324 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
328 modest_main_window_init (ModestMainWindow *obj)
330 ModestMainWindowPrivate *priv;
332 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
334 priv->queue_err_signals = NULL;
335 priv->msg_paned = NULL;
336 priv->main_paned = NULL;
337 priv->main_vbox = NULL;
338 priv->header_view = NULL;
339 priv->folder_view = NULL;
340 priv->contents_widget = NULL;
341 priv->accounts_popup = NULL;
342 priv->details_widget = NULL;
343 priv->empty_view = NULL;
344 priv->progress_widgets = NULL;
345 priv->progress_bar = NULL;
346 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
347 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
348 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
349 priv->merge_ids = NULL;
350 priv->optimized_view = FALSE;
351 priv->send_receive_in_progress = FALSE;
352 priv->progress_bar_timeout = 0;
353 priv->restore_paned_timeout = 0;
354 priv->sighandlers = NULL;
355 priv->updating_banner = NULL;
356 priv->updating_banner_timeout = 0;
358 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
360 "applications_email_mainview");
364 modest_main_window_finalize (GObject *obj)
366 ModestMainWindowPrivate *priv;
368 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
370 /* Sanity check: shouldn't be needed, the window mgr should
371 call this function before */
372 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
374 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
376 g_slist_free (priv->progress_widgets);
378 g_byte_array_free (priv->merge_ids, TRUE);
380 if (priv->progress_bar_timeout > 0) {
381 g_source_remove (priv->progress_bar_timeout);
382 priv->progress_bar_timeout = 0;
385 if (priv->updating_banner_timeout > 0) {
386 g_source_remove (priv->updating_banner_timeout);
387 priv->updating_banner_timeout = 0;
390 if (priv->restore_paned_timeout > 0) {
391 g_source_remove (priv->restore_paned_timeout);
392 priv->restore_paned_timeout = 0;
395 G_OBJECT_CLASS(parent_class)->finalize (obj);
399 modest_main_window_get_child_widget (ModestMainWindow *self,
400 ModestMainWindowWidgetType widget_type)
402 ModestMainWindowPrivate *priv;
405 g_return_val_if_fail (self, NULL);
406 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
409 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
411 switch (widget_type) {
412 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
413 widget = (GtkWidget*)priv->header_view; break;
414 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
415 widget = (GtkWidget*)priv->folder_view; break;
420 return widget ? GTK_WIDGET(widget) : NULL;
424 restore_paned_timeout_handler (gpointer *data)
426 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
427 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
430 if (GTK_WIDGET_VISIBLE (main_window)) {
431 conf = modest_runtime_get_conf ();
432 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
433 MODEST_CONF_MAIN_PANED_KEY);
440 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
443 ModestMainWindowPrivate *priv;
445 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
447 conf = modest_runtime_get_conf ();
449 modest_widget_memory_restore (conf, G_OBJECT(self),
450 MODEST_CONF_MAIN_WINDOW_KEY);
452 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
453 MODEST_CONF_HEADER_VIEW_KEY);
455 if (do_folder_view_too)
456 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
457 MODEST_CONF_FOLDER_VIEW_KEY);
459 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
460 MODEST_CONF_MAIN_PANED_KEY);
462 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
464 /* We need to force a redraw here in order to get the right
465 position of the horizontal paned separator */
466 gtk_widget_show (GTK_WIDGET (self));
471 save_state (ModestWindow *window)
474 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
475 ModestMainWindowPrivate *priv;
477 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
478 conf = modest_runtime_get_conf ();
480 modest_widget_memory_save (conf,G_OBJECT(self),
481 MODEST_CONF_MAIN_WINDOW_KEY);
482 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
483 MODEST_CONF_MAIN_PANED_KEY);
484 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
485 // MODEST_CONF_HEADER_VIEW_KEY);
486 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
487 MODEST_CONF_FOLDER_VIEW_KEY);
491 compare_display_names (ModestAccountData *a,
492 ModestAccountData *b)
494 return strcmp (a->display_name, b->display_name);
498 update_menus (ModestMainWindow* self)
500 GSList *account_names, *iter, *accounts;
501 ModestMainWindowPrivate *priv;
502 ModestWindowPrivate *parent_priv;
503 ModestAccountMgr *mgr;
504 gint i, num_accounts;
506 gchar *default_account;
507 const gchar *active_account_name;
508 GtkWidget *send_receive_button, *item;
509 GtkAction *send_receive_all = NULL;
512 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
513 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
515 /* Get enabled account IDs */
516 mgr = modest_runtime_get_account_mgr ();
517 account_names = modest_account_mgr_account_names (mgr, TRUE);
518 iter = account_names;
522 ModestAccountData *account_data =
523 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
524 accounts = g_slist_prepend (accounts, account_data);
528 modest_account_mgr_free_account_names (account_names);
529 account_names = NULL;
531 /* Order the list of accounts by its display name */
532 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
533 num_accounts = g_slist_length (accounts);
535 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
536 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
537 gtk_action_set_visible (send_receive_all, num_accounts > 1);
539 /* Delete old send&receive popup items. We can not just do a
540 menu_detach because it does not work well with
542 if (priv->accounts_popup)
543 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
544 (GtkCallback) gtk_widget_destroy, NULL);
546 /* Delete old entries in the View menu. Do not free groups, it
548 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
550 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
551 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
552 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
553 GTK_ACTION_GROUP (groups->data));
556 if (priv->merge_ids) {
557 for (i = 0; i < priv->merge_ids->len; i++)
558 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
559 g_byte_array_free (priv->merge_ids, TRUE);
561 /* We need to call this in order to ensure
562 that the new actions are added in the right
563 order (alphabetical) */
564 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
566 groups = g_list_next (groups);
568 priv->merge_ids = g_byte_array_sized_new (num_accounts);
570 /* Get send receive button */
571 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
572 "/ToolBar/ToolbarSendReceive");
574 /* Create the menu */
575 if (num_accounts > 1) {
576 if (!priv->accounts_popup)
577 priv->accounts_popup = gtk_menu_new ();
578 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
579 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
580 g_signal_connect (G_OBJECT (item),
582 G_CALLBACK (on_send_receive_csm_activated),
584 item = gtk_separator_menu_item_new ();
585 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
588 /* Create a new action group */
589 default_account = modest_account_mgr_get_default_account (mgr);
590 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
592 if (active_account_name == NULL)
594 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
597 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
599 for (i = 0; i < num_accounts; i++) {
600 gchar *display_name = NULL;
601 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
603 if (default_account && account_data->account_name &&
604 !(strcmp (default_account, account_data->account_name) == 0)) {
605 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
606 account_data->display_name);
609 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
610 account_data->display_name);
613 /* Create action and add it to the action group. The
614 action name must be the account name, this way we
615 could know in the handlers the account to show */
616 if(account_data && account_data->account_name) {
617 gchar* item_name, *refresh_action_name;
619 GtkAction *view_account_action, *refresh_account_action;
621 view_account_action = GTK_ACTION (gtk_radio_action_new (account_data->account_name,
622 display_name, NULL, NULL, 0));
623 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
624 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
625 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
627 if (active_account_name) {
628 if (active_account_name && account_data->account_name &&
629 (strcmp (active_account_name, account_data->account_name) == 0)) {
630 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
634 /* Add ui from account data. We allow 2^9-1 account
635 changes in a single execution because we're
636 downcasting the guint to a guint8 in order to use a
637 GByteArray. It should be enough. */
638 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
639 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
640 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
641 gtk_ui_manager_add_ui (parent_priv->ui_manager,
643 "/MenuBar/ViewMenu/ViewMenuAdditions",
645 account_data->account_name,
646 GTK_UI_MANAGER_MENUITEM,
649 /* Connect the action signal "activate" */
650 g_signal_connect_after (G_OBJECT (view_account_action),
652 G_CALLBACK (on_show_account_action_toggled),
655 /* Create the items for the Tools->Send&Receive submenu */
656 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
657 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
658 display_name, NULL, NULL);
659 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
661 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
662 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
663 gtk_ui_manager_add_ui (parent_priv->ui_manager,
665 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
668 GTK_UI_MANAGER_MENUITEM,
670 g_free (refresh_action_name);
672 g_signal_connect_data (G_OBJECT (refresh_account_action),
674 G_CALLBACK (on_refresh_account_action_activated),
675 g_strdup (account_data->account_name),
676 (GClosureNotify) g_free,
679 /* Create item and add it to the send&receive
680 CSM. If there is only one account then
682 if (priv->accounts_popup) {
683 GtkWidget *label = gtk_label_new(NULL);
684 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
685 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
687 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
688 gtk_label_set_markup (GTK_LABEL (label), escaped);
693 gtk_label_set_text (GTK_LABEL (label), display_name);
696 item = gtk_menu_item_new ();
697 gtk_container_add (GTK_CONTAINER (item), label);
699 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
700 g_signal_connect_data (G_OBJECT (item),
702 G_CALLBACK (on_send_receive_csm_activated),
703 g_strdup (account_data->account_name),
704 (GClosureNotify) g_free,
711 g_free (display_name);
714 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
716 /* We cannot do this in the loop above because this relies on the action
717 * group being inserted. This makes the default account appear in bold.
718 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
719 for (i = 0; i < num_accounts; i++) {
720 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
722 if(account_data->account_name && default_account &&
723 strcmp (account_data->account_name, default_account) == 0) {
724 gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
726 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
727 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
731 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
732 if (GTK_IS_LABEL (child)) {
733 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
734 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
735 gtk_label_set_markup (GTK_LABEL (child), bold_name);
740 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
741 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
745 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
746 if (GTK_IS_LABEL (child)) {
747 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
748 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
749 gtk_label_set_markup (GTK_LABEL (child), bold_name);
757 modest_account_mgr_free_account_data (mgr, account_data);
760 if (priv->accounts_popup) {
761 /* Mandatory in order to view the menu contents */
762 gtk_widget_show_all (priv->accounts_popup);
764 /* Setup tap_and_hold just if was not done before*/
765 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
766 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
770 g_slist_free (accounts);
771 g_free (default_account);
774 /* Make sure that at least one account is viewed if there are any
775 * accounts, for instance when adding the first account: */
776 set_at_least_one_account_visible (self);
780 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
782 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
783 gtk_scrolled_window_add_with_viewport
784 (GTK_SCROLLED_WINDOW(win), widget);
786 gtk_container_add (GTK_CONTAINER(win),
797 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
799 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
801 GList *oerrsignals = priv->queue_err_signals;
802 while (oerrsignals) {
803 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
804 g_signal_handler_disconnect (esignal->queue, esignal->signal);
805 g_slice_free (QueueErrorSignal, esignal);
806 oerrsignals = g_list_next (oerrsignals);
808 g_list_free (priv->queue_err_signals);
809 priv->queue_err_signals = NULL;
814 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
816 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
819 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
823 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
825 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
827 /* Update visibility */
830 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
834 modest_main_window_disconnect_signals (ModestWindow *self)
836 ModestMainWindowPrivate *priv;
837 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
839 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
840 priv->sighandlers = NULL;
844 connect_signals (ModestMainWindow *self)
846 ModestWindowPrivate *parent_priv;
847 ModestMainWindowPrivate *priv;
850 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
851 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
856 modest_signal_mgr_connect (priv->sighandlers,
857 G_OBJECT(priv->folder_view), "key-press-event",
858 G_CALLBACK(on_inner_widgets_key_pressed), self);
860 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "folder_selection_changed",
861 G_CALLBACK (modest_main_window_on_folder_selection_changed), self);
863 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
864 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), self);
866 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event",
867 G_CALLBACK (on_folder_view_focus_in), self);
869 /* Folder view CSM */
870 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
871 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
872 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
873 G_CALLBACK(_folder_view_csm_menu_activated),
877 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
878 G_CALLBACK(modest_ui_actions_on_header_selected), self);
880 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
881 G_CALLBACK(modest_ui_actions_on_header_activated), self);
883 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
884 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
886 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
887 G_CALLBACK(on_inner_widgets_key_pressed), self);
889 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
890 G_CALLBACK(on_msg_count_changed), self);
892 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
893 G_CALLBACK (on_header_view_focus_in), self);
895 modest_signal_mgr_connect (priv->sighandlers,
896 G_OBJECT (priv->header_view),
898 G_CALLBACK (on_updating_msg_list),
901 /* Header view CSM */
902 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
903 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
905 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
906 G_CALLBACK(_header_view_csm_menu_activated),
911 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
912 G_CALLBACK (modest_main_window_window_state_event),
915 /* Mail Operation Queue */
917 modest_signal_mgr_connect (priv->sighandlers,
918 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
920 G_CALLBACK (on_queue_changed), self);
922 /* Track changes in the device name */
924 modest_signal_mgr_connect (priv->sighandlers,
925 G_OBJECT(modest_runtime_get_conf ()),
927 G_CALLBACK (on_configuration_key_changed),
930 /* Track account changes. We need to refresh the toolbar */
932 modest_signal_mgr_connect (priv->sighandlers,
933 G_OBJECT (modest_runtime_get_account_store ()),
935 G_CALLBACK (on_account_inserted),
938 modest_signal_mgr_connect (priv->sighandlers,
939 G_OBJECT (modest_runtime_get_account_store ()),
941 G_CALLBACK (on_account_removed),
944 /* We need to refresh the send & receive menu to change the bold
945 * account when the default account changes. */
947 modest_signal_mgr_connect (priv->sighandlers,
948 G_OBJECT (modest_runtime_get_account_mgr ()),
949 "default_account_changed",
950 G_CALLBACK (on_default_account_changed),
955 modest_signal_mgr_connect (priv->sighandlers,
956 G_OBJECT (modest_runtime_get_account_store()),
957 "password_requested",
958 G_CALLBACK (modest_ui_actions_on_password_requested),
963 /** Idle handler, to send/receive at startup .*/
965 sync_accounts_cb (ModestMainWindow *win)
967 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
968 return FALSE; /* Do not call this idle handler again. */
973 on_hildon_program_is_topmost_notify(GObject *self,
974 GParamSpec *propert_param, gpointer user_data)
976 HildonProgram *app = HILDON_PROGRAM (self);
979 ModestWindow* self = MODEST_WINDOW(user_data);
982 /* Note that use of hildon_program_set_can_hibernate()
983 * is generally referred to as "setting the killable flag",
984 * though hibernation does not seem equal to death.
987 if (hildon_program_get_is_topmost (app)) {
988 /* Prevent hibernation when the progam comes to the foreground,
989 * because hibernation should only happen when the application
990 * is in the background: */
991 hildon_program_set_can_hibernate (app, FALSE);
993 /* Allow hibernation if the program has gone to the background: */
995 /* However, prevent hibernation while the settings are being changed: */
996 const gboolean hibernation_prevented =
997 modest_window_mgr_get_hibernation_is_prevented (
998 modest_runtime_get_window_mgr ());
1000 if (hibernation_prevented)
1001 hildon_program_set_can_hibernate (app, FALSE);
1003 /* Allow hibernation, after saving the state: */
1004 modest_osso_save_state();
1005 hildon_program_set_can_hibernate (app, TRUE);
1012 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1014 GtkWidget *folder_win = (GtkWidget *) user_data;
1015 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1017 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1018 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1019 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
1021 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1023 /* Connect signals */
1024 connect_signals (MODEST_MAIN_WINDOW (self));
1026 /* Set account store */
1027 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1028 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1030 /* Load previous osso state, for instance if we are being restored from
1032 modest_osso_load_state ();
1034 /* Restore window & widget settings */
1035 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1037 /* /\* The UI spec wants us to show a connection dialog when the application is */
1038 /* * started by the user, if there is no connection. */
1039 /* * Do this before showing the account wizard, */
1040 /* * because wizard needs a connection to discover capabilities. *\/ */
1041 /* modest_platform_connect_and_wait (GTK_WINDOW (self), NULL); */
1043 /* Check if accounts exist and show the account wizard if not */
1044 gboolean accounts_exist =
1045 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1047 if (!accounts_exist) {
1048 /* This is necessary to have the main window shown behind the dialog
1049 It's an ugly hack... jschmid */
1050 gtk_widget_show_all(GTK_WIDGET(self));
1051 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1054 GtkAction *send_receive_all;
1055 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1056 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1057 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1058 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1059 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1060 modest_account_mgr_free_account_names (accounts);
1061 update_menus (MODEST_MAIN_WINDOW (self));
1066 modest_main_window_new (void)
1068 ModestMainWindow *self = NULL;
1069 ModestMainWindowPrivate *priv = NULL;
1070 ModestWindowPrivate *parent_priv = NULL;
1071 GtkWidget *folder_win = NULL;
1072 ModestDimmingRulesGroup *menu_rules_group = NULL;
1073 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1074 GtkActionGroup *action_group = NULL;
1075 GError *error = NULL;
1076 ModestConf *conf = NULL;
1077 GtkAction *action = NULL;
1078 GdkPixbuf *window_icon;
1080 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1081 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1082 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1084 parent_priv->ui_manager = gtk_ui_manager_new();
1085 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1087 action_group = gtk_action_group_new ("ModestMainWindowActions");
1088 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1090 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1091 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1093 /* Add common actions */
1094 gtk_action_group_add_actions (action_group,
1095 modest_action_entries,
1096 G_N_ELEMENTS (modest_action_entries),
1099 gtk_action_group_add_actions (action_group,
1100 modest_folder_view_action_entries,
1101 G_N_ELEMENTS (modest_folder_view_action_entries),
1104 gtk_action_group_add_actions (action_group,
1105 modest_header_view_action_entries,
1106 G_N_ELEMENTS (modest_header_view_action_entries),
1109 gtk_action_group_add_toggle_actions (action_group,
1110 modest_toggle_action_entries,
1111 G_N_ELEMENTS (modest_toggle_action_entries),
1114 gtk_action_group_add_toggle_actions (action_group,
1115 modest_main_window_toggle_action_entries,
1116 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1119 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1120 g_object_unref (action_group);
1122 /* Load the UI definition */
1123 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1124 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1125 if (error != NULL) {
1126 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1127 g_error_free (error);
1131 /* Add common dimming rules */
1132 modest_dimming_rules_group_add_rules (menu_rules_group,
1133 modest_main_window_menu_dimming_entries,
1134 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1135 MODEST_WINDOW (self));
1136 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1137 modest_main_window_toolbar_dimming_entries,
1138 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1139 MODEST_WINDOW (self));
1141 /* Insert dimming rules group for this window */
1142 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1143 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1144 g_object_unref (menu_rules_group);
1145 g_object_unref (toolbar_rules_group);
1147 /* Add accelerators */
1148 gtk_window_add_accel_group (GTK_WINDOW (self),
1149 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1151 /* Menubar. Update the state of some toggles */
1152 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1153 conf = modest_runtime_get_conf ();
1154 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1155 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1156 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1157 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1158 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1159 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1160 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1161 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1162 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1163 gtk_widget_show (parent_priv->menubar);
1165 /* Get device name */
1166 modest_maemo_utils_get_device_name ();
1170 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1171 if (!priv->header_view)
1172 g_printerr ("modest: cannot instantiate header view\n");
1173 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1174 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1175 MODEST_CONF_HEADER_VIEW_KEY);
1177 /* Other style properties of header view */
1178 g_object_set (G_OBJECT (priv->header_view),
1179 "rules-hint", FALSE,
1181 /* gtk_widget_show (priv->header_view); */
1184 priv->empty_view = create_empty_view ();
1185 gtk_widget_show (priv->empty_view);
1187 /* Create scrolled windows */
1188 folder_win = gtk_scrolled_window_new (NULL, NULL);
1189 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1190 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1192 GTK_POLICY_AUTOMATIC);
1193 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1195 GTK_POLICY_AUTOMATIC);
1196 /* gtk_widget_show (priv->contents_widget); */
1199 priv->main_paned = gtk_hpaned_new ();
1200 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1201 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1202 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1204 /* putting it all together... */
1205 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1206 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1207 gtk_widget_show (priv->main_vbox);
1209 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1211 HildonProgram *app = hildon_program_get_instance ();
1212 hildon_program_add_window (app, HILDON_WINDOW (self));
1214 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1215 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1217 g_signal_connect (G_OBJECT(self), "show",
1218 G_CALLBACK (modest_main_window_on_show), folder_win);
1220 /* Set window icon */
1221 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1223 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1224 g_object_unref (window_icon);
1227 /* Dont't restore settings here,
1228 * because it requires a gtk_widget_show(),
1229 * and we don't want to do that until later,
1230 * so that the UI is not visible for non-menu D-Bus activation.
1232 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1234 return MODEST_WINDOW(self);
1238 modest_main_window_set_style (ModestMainWindow *self,
1239 ModestMainWindowStyle style)
1241 ModestMainWindowPrivate *priv;
1242 ModestWindowPrivate *parent_priv;
1246 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1248 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1249 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1251 /* no change -> nothing to do */
1252 if (priv->style == style)
1255 /* Get toggle button and update the state if needed. This will
1256 happen only when the set_style is not invoked from the UI,
1257 for example when it's called from widget memory */
1258 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1259 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1260 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1261 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1262 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1263 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1264 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1267 priv->style = style;
1269 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1270 /* Remove main paned */
1271 g_object_ref (priv->main_paned);
1272 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1274 /* Reparent the contents widget to the main vbox */
1275 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1278 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1279 /* Remove header view */
1280 g_object_ref (priv->contents_widget);
1281 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1283 /* Reparent the main paned */
1284 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1285 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1289 g_return_if_reached ();
1292 /* Let header view grab the focus if it's being shown */
1293 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1294 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1296 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1299 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1302 ModestMainWindowStyle
1303 modest_main_window_get_style (ModestMainWindow *self)
1305 ModestMainWindowPrivate *priv;
1307 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1309 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1316 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1318 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1319 ModestWindowPrivate *parent_priv;
1320 ModestWindowMgr *mgr;
1321 gboolean is_fullscreen;
1322 GtkAction *fs_toggle_action;
1325 mgr = modest_runtime_get_window_mgr ();
1327 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1329 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1331 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1332 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1333 if (is_fullscreen != active) {
1334 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1343 set_homogeneous (GtkWidget *widget,
1346 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1347 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1351 modest_main_window_show_toolbar (ModestWindow *self,
1352 gboolean show_toolbar)
1354 ModestMainWindowPrivate *priv = NULL;
1355 ModestWindowPrivate *parent_priv = NULL;
1356 GtkWidget *reply_button = NULL, *menu = NULL;
1357 GtkWidget *placeholder = NULL;
1359 const gchar *action_name;
1362 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1363 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1364 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1366 /* Set optimized view status */
1367 priv->optimized_view = !show_toolbar;
1369 if (!parent_priv->toolbar) {
1370 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1372 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1374 /* Set homogeneous toolbar */
1375 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1376 set_homogeneous, NULL);
1378 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1379 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1380 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1381 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1382 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1383 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1384 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1385 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1387 /* Add ProgressBar (Transfer toolbar) */
1388 priv->progress_bar = modest_progress_bar_widget_new ();
1389 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1390 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1391 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1392 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1393 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1395 /* Connect cancel 'clicked' signal to abort progress mode */
1396 g_signal_connect(priv->cancel_toolitem, "clicked",
1397 G_CALLBACK(cancel_progressbar),
1400 /* Add it to the observers list */
1401 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1404 hildon_window_add_toolbar (HILDON_WINDOW (self),
1405 GTK_TOOLBAR (parent_priv->toolbar));
1407 /* Set reply button tap and hold menu */
1408 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1409 "/ToolBar/ToolbarMessageReply");
1410 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1411 "/ToolbarReplyCSM");
1412 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1414 /* Set send & receive button tap and hold menu */
1415 update_menus (MODEST_MAIN_WINDOW (self));
1419 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1420 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1421 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1423 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1424 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1426 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1430 /* Update also the actions (to update the toggles in the
1431 menus), we have to do it manually because some other window
1432 of the same time could have changed it (remember that the
1433 toolbar fullscreen mode is shared by all the windows of the
1435 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1436 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1438 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1440 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1441 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1446 on_account_inserted (TnyAccountStore *accoust_store,
1447 TnyAccount *account,
1450 update_menus (MODEST_MAIN_WINDOW (user_data));
1454 on_default_account_changed (ModestAccountMgr* mgr,
1457 update_menus (MODEST_MAIN_WINDOW (user_data));
1461 on_account_removed (TnyAccountStore *accoust_store,
1462 TnyAccount *account,
1465 update_menus (MODEST_MAIN_WINDOW (user_data));
1469 * This function manages the key events used to navigate between
1470 * header and folder views (when the window is in split view)
1473 * -------------------------------------------------
1474 * HeaderView GDK_Left Move focus to folder view
1475 * FolderView GDK_Right Move focus to header view
1477 * There is no need to scroll to selected row, the widgets will be the
1478 * responsibles of doing that (probably managing the focus-in event
1481 on_inner_widgets_key_pressed (GtkWidget *widget,
1485 ModestMainWindowPrivate *priv;
1487 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1489 /* Do nothing if we're in SIMPLE style */
1490 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1493 if (MODEST_IS_HEADER_VIEW (widget)) {
1494 if (event->keyval == GDK_Left)
1495 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1496 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1497 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1498 if (selected_headers > 1) {
1499 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1503 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1504 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1510 set_alignment (GtkWidget *widget,
1513 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1514 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1518 create_empty_view (void)
1520 GtkLabel *label = NULL;
1521 GtkWidget *align = NULL;
1523 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1524 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1525 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1526 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1528 return GTK_WIDGET(align);
1532 * Free the returned string
1535 get_gray_color_markup (GtkWidget *styled_widget)
1537 gchar *gray_color_markup;
1539 /* Obtain the secondary text color. We need a realized widget, that's why
1540 we get styled_widget from outside */
1541 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1543 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1544 gray_color_markup = modest_text_utils_get_color_string (&color);
1546 gray_color_markup = g_strdup ("#BBBBBB");
1548 return gray_color_markup;
1552 * Free the returned string
1555 create_device_name_visual_string (const gchar *device_name,
1556 const gchar *gray_color_markup)
1560 /* We have to use "" to fill the %s of the translation. We can
1561 not just use the device name because the device name is
1562 shown in a different color, so it could not be included
1563 into the <span> tag */
1564 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1565 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1575 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1577 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1582 gchar *gray_color_markup;
1584 vbox = gtk_vbox_new (FALSE, 0);
1586 gray_color_markup = get_gray_color_markup (styled_widget);
1588 /* Account description: */
1589 if (modest_tny_account_is_virtual_local_folders (account)
1590 || (modest_tny_account_is_memory_card_account (account))) {
1592 /* Get device name */
1593 gchar *device_name = NULL;
1594 if (modest_tny_account_is_virtual_local_folders (account))
1595 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1596 MODEST_CONF_DEVICE_NAME, NULL);
1598 device_name = g_strdup (tny_account_get_name (account));
1600 label = create_device_name_visual_string ((const gchar *) device_name,
1601 (const gchar *) gray_color_markup);
1602 label_w = gtk_label_new (NULL);
1603 gtk_label_set_markup (GTK_LABEL (label_w), label);
1604 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1605 g_free (device_name);
1608 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1609 gtk_box_pack_start (GTK_BOX (vbox),
1610 gtk_label_new (tny_account_get_name (account)),
1613 /* Other accounts, such as IMAP and POP: */
1618 /* Put proto in uppercase */
1619 proto = g_string_new (tny_account_get_proto (account));
1620 proto = g_string_ascii_up (proto);
1622 /* note: mcen_fi_localroot_description is something like "%s account"
1623 * however, we should display "%s account: %s"... therefore, ugly tmp */
1624 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1625 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1626 gray_color_markup, tmp, tny_account_get_name (account));
1629 label_w = gtk_label_new (NULL);
1630 gtk_label_set_markup (GTK_LABEL (label_w), label);
1631 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1632 g_string_free (proto, TRUE);
1638 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1639 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1640 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1641 modest_tny_folder_store_get_message_count (folder_store));
1642 label_w = gtk_label_new (NULL);
1643 gtk_label_set_markup (GTK_LABEL (label_w), label);
1644 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1648 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1650 _("mcen_fi_rootfolder_folders"),
1651 modest_tny_folder_store_get_folder_count (folder_store));
1652 label_w = gtk_label_new (NULL);
1653 gtk_label_set_markup (GTK_LABEL (label_w), label);
1654 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1658 if (modest_tny_account_is_virtual_local_folders (account)
1659 || modest_tny_account_is_memory_card_account (account)) {
1661 gchar *size = modest_text_utils_get_display_size (
1662 modest_tny_folder_store_get_local_size (folder_store));
1664 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1665 gray_color_markup, _("mcen_fi_rootfolder_size"),
1669 label_w = gtk_label_new (NULL);
1670 gtk_label_set_markup (GTK_LABEL (label_w), label);
1671 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1673 } else if (TNY_IS_ACCOUNT(folder_store)) {
1674 TnyAccount *account = TNY_ACCOUNT(folder_store);
1676 time_t last_updated;
1677 const gchar *last_updated_string;
1678 /* Get last updated from configuration */
1679 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1680 tny_account_get_id (account));
1682 if (last_updated > 0)
1683 last_updated_string = modest_text_utils_get_display_date(last_updated);
1685 last_updated_string = g_strdup (_("mcen_va_never"));
1687 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1688 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1689 label_w = gtk_label_new (NULL);
1690 gtk_label_set_markup (GTK_LABEL (label_w), label);
1691 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1695 g_free (gray_color_markup);
1698 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1704 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1706 ModestMainWindowPrivate *priv = NULL;
1708 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1710 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1712 return priv->send_receive_in_progress;
1716 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1718 GtkAction *action = NULL;
1719 GtkWidget *widget = NULL;
1720 ModestMainWindowPrivate *priv = NULL;
1722 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1723 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1725 priv->send_receive_in_progress = TRUE;
1727 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1728 gtk_action_set_sensitive (action, FALSE);
1729 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1730 /* gtk_action_set_sensitive (action, FALSE); */
1731 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1732 gtk_widget_set_sensitive (widget, FALSE);
1736 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1738 GtkAction *action = NULL;
1739 GtkWidget *widget = NULL;
1740 ModestMainWindowPrivate *priv = NULL;
1742 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1743 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1745 priv->send_receive_in_progress = FALSE;
1747 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1748 gtk_action_set_sensitive (action, TRUE);
1749 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1750 /* gtk_action_set_sensitive (action, TRUE); */
1751 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1752 gtk_widget_set_sensitive (widget, TRUE);
1757 on_msg_count_changed (ModestHeaderView *header_view,
1759 TnyFolderChange *change,
1760 ModestMainWindow *main_window)
1762 gboolean folder_empty = FALSE;
1763 gboolean all_marked_as_deleted = FALSE;
1764 TnyFolderChangeChanged changed;
1765 ModestMainWindowPrivate *priv;
1767 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1768 g_return_if_fail (TNY_IS_FOLDER(folder));
1769 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1770 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1772 changed = tny_folder_change_get_changed (change);
1774 /* If something changes */
1775 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1776 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1778 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1780 /* Check header removed (hide marked as DELETED headers) */
1781 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1782 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1785 /* Check if all messages are marked to be deleted */
1786 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1787 folder_empty = folder_empty || all_marked_as_deleted ;
1789 /* Set contents style of headers view */
1791 modest_main_window_set_contents_style (main_window,
1792 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1793 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1796 modest_main_window_set_contents_style (main_window,
1797 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1803 modest_main_window_set_contents_style (ModestMainWindow *self,
1804 ModestMainWindowContentsStyle style)
1806 ModestMainWindowPrivate *priv;
1808 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1810 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1812 /* We allow to set the same content style than the previously
1813 set if there are details, because it could happen when we're
1814 selecting different accounts consecutively */
1815 if ((priv->contents_style == style) &&
1816 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1819 /* Remove previous child. Delete it if it was an account
1821 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1823 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1824 g_object_ref (content);
1825 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1826 g_object_ref (priv->empty_view);
1827 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1830 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1833 priv->contents_style = style;
1835 switch (priv->contents_style) {
1836 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1837 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1838 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1841 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1843 /* if we're started without main win, there may not be a folder
1844 * view. this fixes a GLib-Critical */
1845 if (priv->folder_view) {
1846 TnyFolderStore *selected_folderstore =
1847 modest_folder_view_get_selected (priv->folder_view);
1848 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1849 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1850 TNY_ACCOUNT (selected_folderstore));
1852 wrap_in_scrolled_window (priv->contents_widget,
1853 priv->details_widget);
1855 g_object_unref (selected_folderstore);
1856 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1861 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1862 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1863 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1867 g_return_if_reached ();
1871 gtk_widget_show_all (priv->contents_widget);
1874 ModestMainWindowContentsStyle
1875 modest_main_window_get_contents_style (ModestMainWindow *self)
1877 ModestMainWindowPrivate *priv;
1879 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1881 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1882 return priv->contents_style;
1887 on_configuration_key_changed (ModestConf* conf,
1889 ModestConfEvent event,
1890 ModestConfNotificationId id,
1891 ModestMainWindow *self)
1893 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1894 TnyAccount *account = NULL;
1896 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1899 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1902 if (priv->folder_view)
1903 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1905 if (account && TNY_IS_ACCOUNT (account) &&
1906 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1909 const gchar *device_name;
1910 gchar *new_text, *gray_color_markup;
1913 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1914 label = GTK_LABEL (children->data);
1916 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1917 MODEST_CONF_DEVICE_NAME, NULL);
1919 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1920 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1922 gtk_label_set_markup (label, new_text);
1923 gtk_widget_show (GTK_WIDGET (label));
1925 g_free (gray_color_markup);
1927 g_list_free (children);
1929 g_object_unref (account);
1933 set_toolbar_transfer_mode (ModestMainWindow *self)
1935 ModestMainWindowPrivate *priv = NULL;
1937 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1939 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1941 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1943 if (priv->progress_bar_timeout > 0) {
1944 g_source_remove (priv->progress_bar_timeout);
1945 priv->progress_bar_timeout = 0;
1952 set_toolbar_mode (ModestMainWindow *self,
1953 ModestToolBarModes mode)
1955 ModestWindowPrivate *parent_priv = NULL;
1956 ModestMainWindowPrivate *priv = NULL;
1957 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1959 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1961 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1962 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1964 /* In case this was called before the toolbar exists: */
1965 if (!(parent_priv->toolbar))
1968 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1970 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1971 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1972 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1974 /* Sets current toolbar mode */
1975 priv->current_toolbar_mode = mode;
1977 /* Checks the dimming rules */
1978 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1980 /* Show and hide toolbar items */
1982 case TOOLBAR_MODE_NORMAL:
1984 gtk_action_set_visible (sort_action, TRUE);
1986 gtk_action_set_visible (refresh_action, TRUE);
1987 if (priv->progress_toolitem) {
1988 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1989 gtk_widget_hide (priv->progress_toolitem);
1991 if (priv->progress_bar)
1992 gtk_widget_hide (priv->progress_bar);
1995 gtk_action_set_visible (cancel_action, FALSE);
1997 /* Hide toolbar if optimized view is enabled */
1998 if (priv->optimized_view)
1999 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2001 case TOOLBAR_MODE_TRANSFER:
2003 gtk_action_set_visible (sort_action, FALSE);
2005 gtk_action_set_visible (refresh_action, FALSE);
2007 gtk_action_set_visible (cancel_action, TRUE);
2008 if (priv->progress_toolitem) {
2009 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2010 gtk_widget_show (priv->progress_toolitem);
2012 if (priv->progress_bar)
2013 gtk_widget_show (priv->progress_bar);
2015 /* Show toolbar if it's hiden (optimized view ) */
2016 if (priv->optimized_view)
2017 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2020 g_return_if_reached ();
2025 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2027 ModestMainWindowPrivate *priv;
2029 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2030 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2032 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2036 cancel_progressbar (GtkToolButton *toolbutton,
2037 ModestMainWindow *self)
2040 ModestMainWindowPrivate *priv;
2042 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2044 /* Get operation observers and cancel all the operations */
2045 tmp = priv->progress_widgets;
2047 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2048 tmp=g_slist_next(tmp);
2053 observers_empty (ModestMainWindow *self)
2056 ModestMainWindowPrivate *priv;
2057 gboolean is_empty = TRUE;
2058 guint pending_ops = 0;
2060 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2061 tmp = priv->progress_widgets;
2063 /* Check all observers */
2064 while (tmp && is_empty) {
2065 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2066 is_empty = pending_ops == 0;
2068 tmp = g_slist_next(tmp);
2076 * Gets the toolbar mode needed for each mail operation. It stores in
2077 * @mode_changed if the toolbar mode has changed or not
2079 static ModestToolBarModes
2080 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2081 ModestMailOperation *mail_op,
2082 gboolean *mode_changed)
2084 ModestToolBarModes mode;
2085 ModestMainWindowPrivate *priv;
2087 *mode_changed = FALSE;
2088 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2090 /* Get toolbar mode from operation id*/
2091 switch (modest_mail_operation_get_type_operation (mail_op)) {
2092 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2093 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2094 mode = TOOLBAR_MODE_TRANSFER;
2095 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2096 *mode_changed = TRUE;
2099 mode = TOOLBAR_MODE_NORMAL;
2105 on_mail_operation_started (ModestMailOperation *mail_op,
2108 ModestMainWindow *self;
2109 ModestMailOperationTypeOperation op_type;
2110 ModestMainWindowPrivate *priv;
2111 ModestToolBarModes mode;
2113 gboolean mode_changed = FALSE;
2114 TnyAccount *account;
2116 self = MODEST_MAIN_WINDOW (user_data);
2117 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2119 /* Do not show progress for receiving operations if the
2120 account is the local account or the MMC one */
2121 op_type = modest_mail_operation_get_type_operation (mail_op);
2122 account = modest_mail_operation_get_account (mail_op);
2123 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2126 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2127 modest_tny_account_is_memory_card_account (account));
2128 g_object_unref (account);
2133 /* Get toolbar mode from operation id*/
2134 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2136 /* Add operation observers and change toolbar if neccessary*/
2137 tmp = priv->progress_widgets;
2138 if (mode == TOOLBAR_MODE_TRANSFER) {
2140 set_toolbar_transfer_mode(self);
2143 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2145 tmp = g_slist_next (tmp);
2151 on_mail_operation_finished (ModestMailOperation *mail_op,
2154 ModestToolBarModes mode;
2155 ModestMailOperationTypeOperation op_type;
2157 ModestMainWindow *self;
2158 gboolean mode_changed;
2159 TnyAccount *account;
2160 ModestMainWindowPrivate *priv;
2162 self = MODEST_MAIN_WINDOW (user_data);
2163 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2165 /* The mail operation was not added to the progress objects if
2166 the account was the local account or the MMC one */
2167 op_type = modest_mail_operation_get_type_operation (mail_op);
2168 account = modest_mail_operation_get_account (mail_op);
2169 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2172 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2173 modest_tny_account_is_memory_card_account (account));
2174 g_object_unref (account);
2179 /* Get toolbar mode from operation id*/
2180 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2182 /* Change toolbar mode */
2183 tmp = priv->progress_widgets;
2184 if (mode == TOOLBAR_MODE_TRANSFER) {
2186 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2188 tmp = g_slist_next (tmp);
2191 /* If no more operations are being observed, NORMAL mode is enabled again */
2192 if (observers_empty (self)) {
2193 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2199 on_queue_changed (ModestMailOperationQueue *queue,
2200 ModestMailOperation *mail_op,
2201 ModestMailOperationQueueNotification type,
2202 ModestMainWindow *self)
2204 ModestMainWindowPrivate *priv;
2206 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2208 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2209 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2211 "operation-started",
2212 G_CALLBACK (on_mail_operation_started),
2214 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2216 "operation-finished",
2217 G_CALLBACK (on_mail_operation_finished),
2219 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2220 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2222 "operation-started");
2223 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2225 "operation-finished");
2230 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2232 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2235 /* Get account data */
2236 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2237 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2239 /* Set the new visible & active account */
2240 if (acc_data && acc_data->store_account) {
2241 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2242 acc_data->store_account->account_name);
2243 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2244 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2245 if (action != NULL) {
2246 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2247 modest_maemo_toggle_action_set_active_block_notify (
2248 GTK_TOGGLE_ACTION (action),
2254 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2259 modest_account_mgr_free_account_data (mgr, acc_data);
2262 /* Make sure that at least one account is "viewed": */
2264 set_at_least_one_account_visible(ModestMainWindow *self)
2266 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2267 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2269 if (!(priv->folder_view)) {
2270 /* It is too early to do this. */
2274 const gchar *active_server_account_name =
2275 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2277 if (!active_server_account_name ||
2278 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2280 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2281 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2282 if (default_modest_name) {
2283 set_account_visible (self, default_modest_name);
2284 } else if (first_modest_name) {
2285 set_account_visible (self, first_modest_name);
2287 g_free (first_modest_name);
2288 g_free (default_modest_name);
2293 on_show_account_action_toggled (GtkToggleAction *action,
2296 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2298 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2299 if (gtk_toggle_action_get_active (action))
2300 set_account_visible (self, acc_name);
2304 refresh_account (const gchar *account_name)
2308 /* win must already exists here, obviously */
2309 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2312 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2316 /* If account_name == NULL, we must update all (option All) */
2318 modest_ui_actions_do_send_receive_all (win);
2320 modest_ui_actions_do_send_receive (account_name, win);
2325 on_refresh_account_action_activated (GtkAction *action,
2328 refresh_account ((const gchar*) user_data);
2332 on_send_receive_csm_activated (GtkMenuItem *item,
2335 refresh_account ((const gchar*) user_data);
2339 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2341 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2343 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2349 on_folder_view_focus_in (GtkWidget *widget,
2350 GdkEventFocus *event,
2353 ModestMainWindow *main_window = NULL;
2355 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2356 main_window = MODEST_MAIN_WINDOW (userdata);
2358 /* Update toolbar dimming state */
2359 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2365 on_header_view_focus_in (GtkWidget *widget,
2366 GdkEventFocus *event,
2369 ModestMainWindow *main_window = NULL;
2370 ModestMainWindowPrivate *priv = NULL;
2372 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2373 main_window = MODEST_MAIN_WINDOW (userdata);
2374 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2376 /* Update toolbar dimming state */
2377 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2383 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2384 TnyFolderStore *folder_store,
2386 ModestMainWindow *main_window)
2388 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2389 GtkAction *action = NULL;
2390 gboolean show_reply = TRUE;
2391 gboolean show_forward = TRUE;
2392 gboolean show_cancel_send = FALSE;
2393 gboolean show_clipboard = TRUE;
2394 gboolean show_delete = TRUE;
2397 if (TNY_IS_ACCOUNT (folder_store)) {
2398 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2399 } else if (TNY_IS_FOLDER (folder_store)) {
2400 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2401 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2402 TNY_FOLDER (folder_store));
2403 switch (folder_type) {
2404 case TNY_FOLDER_TYPE_DRAFTS:
2405 show_clipboard = show_delete = TRUE;
2406 show_reply = show_forward = show_cancel_send = FALSE;
2408 case TNY_FOLDER_TYPE_SENT:
2409 show_forward = show_clipboard = show_delete = TRUE;
2410 show_reply = show_cancel_send = FALSE;
2412 case TNY_FOLDER_TYPE_OUTBOX:
2413 show_clipboard = show_delete = show_cancel_send = TRUE;
2414 show_reply = show_forward = FALSE;
2416 case TNY_FOLDER_TYPE_INVALID:
2417 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2420 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2421 show_cancel_send = FALSE;
2424 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2425 show_cancel_send = FALSE;
2430 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2431 gtk_action_set_visible (action, show_reply);
2432 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2433 gtk_action_set_visible (action, show_reply);
2434 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2435 gtk_action_set_visible (action, show_forward);
2436 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2437 gtk_action_set_visible (action, show_cancel_send);
2438 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2439 gtk_action_set_visible (action, show_delete);
2441 /* We finally call to the ui actions handler, after updating properly
2442 * the header view CSM */
2443 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2447 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2448 GtkTreeModel *model,
2449 GtkTreeRowReference *row_reference,
2450 ModestMainWindow *self)
2452 ModestMainWindowPrivate *priv = NULL;
2453 GtkTreeModel *header_model = NULL;
2454 GtkTreePath *path = NULL;
2456 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2457 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2458 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2460 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2461 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2463 /* Do nothing if we changed the folder in the main view */
2464 if (header_model != model)
2467 /* Select the message in the header view */
2468 path = gtk_tree_row_reference_get_path (row_reference);
2469 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2471 gtk_tree_path_free (path);
2477 show_updating_banner (gpointer user_data)
2479 ModestMainWindowPrivate *priv = NULL;
2481 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2483 priv->updating_banner =
2484 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2485 _CS ("ckdg_pb_updating"));
2487 /* Remove timeout */
2488 priv->updating_banner_timeout = 0;
2493 * We use this function to show/hide a progress banner showing
2494 * "Updating" while the header view is being filled. We're not showing
2495 * it unless the update takes more than 2 seconds
2497 * If starting = TRUE then the refresh is starting, otherwise it means
2498 * that is has just finished
2501 on_updating_msg_list (ModestHeaderView *header_view,
2505 ModestMainWindowPrivate *priv = NULL;
2507 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2509 /* Remove old timeout */
2510 if (priv->updating_banner_timeout > 0) {
2511 g_source_remove (priv->updating_banner_timeout);
2512 priv->updating_banner_timeout = 0;
2515 /* Create a new timeout */
2517 priv->updating_banner_timeout =
2518 g_timeout_add (2000, show_updating_banner, user_data);
2520 /* Remove the banner if exists */
2521 if (priv->updating_banner) {
2522 gtk_widget_destroy (priv->updating_banner);
2523 priv->updating_banner = NULL;