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;
360 modest_main_window_finalize (GObject *obj)
362 ModestMainWindowPrivate *priv;
364 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
366 /* Sanity check: shouldn't be needed, the window mgr should
367 call this function before */
368 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
370 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
372 g_slist_free (priv->progress_widgets);
374 g_byte_array_free (priv->merge_ids, TRUE);
376 if (priv->progress_bar_timeout > 0) {
377 g_source_remove (priv->progress_bar_timeout);
378 priv->progress_bar_timeout = 0;
381 if (priv->updating_banner_timeout > 0) {
382 g_source_remove (priv->updating_banner_timeout);
383 priv->updating_banner_timeout = 0;
386 if (priv->restore_paned_timeout > 0) {
387 g_source_remove (priv->restore_paned_timeout);
388 priv->restore_paned_timeout = 0;
391 G_OBJECT_CLASS(parent_class)->finalize (obj);
395 modest_main_window_get_child_widget (ModestMainWindow *self,
396 ModestMainWindowWidgetType widget_type)
398 ModestMainWindowPrivate *priv;
401 g_return_val_if_fail (self, NULL);
402 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
405 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
407 switch (widget_type) {
408 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
409 widget = (GtkWidget*)priv->header_view; break;
410 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
411 widget = (GtkWidget*)priv->folder_view; break;
416 return widget ? GTK_WIDGET(widget) : NULL;
420 restore_paned_timeout_handler (gpointer *data)
422 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
423 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
426 if (GTK_WIDGET_VISIBLE (main_window)) {
427 conf = modest_runtime_get_conf ();
428 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
429 MODEST_CONF_MAIN_PANED_KEY);
436 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
439 ModestMainWindowPrivate *priv;
441 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
443 conf = modest_runtime_get_conf ();
445 modest_widget_memory_restore (conf, G_OBJECT(self),
446 MODEST_CONF_MAIN_WINDOW_KEY);
448 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
449 MODEST_CONF_HEADER_VIEW_KEY);
451 if (do_folder_view_too)
452 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
453 MODEST_CONF_FOLDER_VIEW_KEY);
455 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
456 MODEST_CONF_MAIN_PANED_KEY);
458 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
460 /* We need to force a redraw here in order to get the right
461 position of the horizontal paned separator */
462 gtk_widget_show (GTK_WIDGET (self));
467 save_state (ModestWindow *window)
470 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
471 ModestMainWindowPrivate *priv;
473 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
474 conf = modest_runtime_get_conf ();
476 modest_widget_memory_save (conf,G_OBJECT(self),
477 MODEST_CONF_MAIN_WINDOW_KEY);
478 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
479 MODEST_CONF_MAIN_PANED_KEY);
480 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
481 // MODEST_CONF_HEADER_VIEW_KEY);
482 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
483 MODEST_CONF_FOLDER_VIEW_KEY);
487 compare_display_names (ModestAccountData *a,
488 ModestAccountData *b)
490 return strcmp (a->display_name, b->display_name);
494 update_menus (ModestMainWindow* self)
496 GSList *account_names, *iter, *accounts;
497 ModestMainWindowPrivate *priv;
498 ModestWindowPrivate *parent_priv;
499 ModestAccountMgr *mgr;
500 gint i, num_accounts;
502 gchar *default_account;
503 GtkWidget *send_receive_button, *item;
504 GtkAction *send_receive_all = NULL;
507 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
508 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
510 /* Get enabled account IDs */
511 mgr = modest_runtime_get_account_mgr ();
512 account_names = modest_account_mgr_account_names (mgr, TRUE);
513 iter = account_names;
517 ModestAccountData *account_data =
518 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
519 accounts = g_slist_prepend (accounts, account_data);
523 modest_account_mgr_free_account_names (account_names);
524 account_names = NULL;
526 /* Order the list of accounts by its display name */
527 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
528 num_accounts = g_slist_length (accounts);
530 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
531 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
532 gtk_action_set_visible (send_receive_all, num_accounts > 1);
534 /* Delete old send&receive popup items. We can not just do a
535 menu_detach because it does not work well with
537 if (priv->accounts_popup)
538 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
539 (GtkCallback) gtk_widget_destroy, NULL);
541 /* Delete old entries in the View menu. Do not free groups, it
543 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
545 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
546 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
547 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
548 GTK_ACTION_GROUP (groups->data));
551 if (priv->merge_ids) {
552 for (i = 0; i < priv->merge_ids->len; i++)
553 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
554 g_byte_array_free (priv->merge_ids, TRUE);
556 /* We need to call this in order to ensure
557 that the new actions are added in the right
558 order (alphabetical) */
559 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
561 groups = g_list_next (groups);
563 priv->merge_ids = g_byte_array_sized_new (num_accounts);
565 /* Get send receive button */
566 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
567 "/ToolBar/ToolbarSendReceive");
569 /* Create the menu */
570 if (num_accounts > 1) {
571 if (!priv->accounts_popup)
572 priv->accounts_popup = gtk_menu_new ();
573 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
574 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
575 g_signal_connect (G_OBJECT (item),
577 G_CALLBACK (on_send_receive_csm_activated),
579 item = gtk_separator_menu_item_new ();
580 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
583 /* Create a new action group */
584 default_account = modest_account_mgr_get_default_account (mgr);
585 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
587 for (i = 0; i < num_accounts; i++) {
588 gchar *display_name = NULL;
589 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
591 if (default_account && account_data->account_name &&
592 !(strcmp (default_account, account_data->account_name) == 0)) {
593 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
594 account_data->display_name);
597 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
598 account_data->display_name);
601 /* Create action and add it to the action group. The
602 action name must be the account name, this way we
603 could know in the handlers the account to show */
604 if(account_data && account_data->account_name) {
605 gchar* item_name, *refresh_action_name;
607 GtkAction *view_account_action, *refresh_account_action;
609 view_account_action = GTK_ACTION (gtk_radio_action_new (account_data->account_name,
610 display_name, NULL, NULL, 0));
611 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
612 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
613 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
615 if (default_account && account_data->account_name &&
616 (strcmp (default_account, account_data->account_name) == 0)) {
617 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
620 /* Add ui from account data. We allow 2^9-1 account
621 changes in a single execution because we're
622 downcasting the guint to a guint8 in order to use a
623 GByteArray. It should be enough. */
624 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
625 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
626 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
627 gtk_ui_manager_add_ui (parent_priv->ui_manager,
629 "/MenuBar/ViewMenu/ViewMenuAdditions",
631 account_data->account_name,
632 GTK_UI_MANAGER_MENUITEM,
635 /* Connect the action signal "activate" */
636 g_signal_connect_after (G_OBJECT (view_account_action),
638 G_CALLBACK (on_show_account_action_toggled),
641 /* Create the items for the Tools->Send&Receive submenu */
642 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
643 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
644 display_name, NULL, NULL);
645 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
647 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
648 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
649 gtk_ui_manager_add_ui (parent_priv->ui_manager,
651 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
654 GTK_UI_MANAGER_MENUITEM,
656 g_free (refresh_action_name);
658 g_signal_connect_data (G_OBJECT (refresh_account_action),
660 G_CALLBACK (on_refresh_account_action_activated),
661 g_strdup (account_data->account_name),
662 (GClosureNotify) g_free,
665 /* Create item and add it to the send&receive
666 CSM. If there is only one account then
668 if (priv->accounts_popup) {
669 GtkWidget *label = gtk_label_new(NULL);
670 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
671 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
673 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
674 gtk_label_set_markup (GTK_LABEL (label), escaped);
679 gtk_label_set_text (GTK_LABEL (label), display_name);
682 item = gtk_menu_item_new ();
683 gtk_container_add (GTK_CONTAINER (item), label);
685 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
686 g_signal_connect_data (G_OBJECT (item),
688 G_CALLBACK (on_send_receive_csm_activated),
689 g_strdup (account_data->account_name),
690 (GClosureNotify) g_free,
697 g_free (display_name);
700 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
702 /* We cannot do this in the loop above because this relies on the action
703 * group being inserted. This makes the default account appear in bold.
704 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
705 for (i = 0; i < num_accounts; i++) {
706 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
708 if(account_data->account_name && default_account &&
709 strcmp (account_data->account_name, default_account) == 0) {
710 gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
712 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
713 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
717 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
718 if (GTK_IS_LABEL (child)) {
719 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
720 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
721 gtk_label_set_markup (GTK_LABEL (child), bold_name);
726 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
727 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);
743 modest_account_mgr_free_account_data (mgr, account_data);
746 if (priv->accounts_popup) {
747 /* Mandatory in order to view the menu contents */
748 gtk_widget_show_all (priv->accounts_popup);
750 /* Setup tap_and_hold just if was not done before*/
751 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
752 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
756 g_slist_free (accounts);
757 g_free (default_account);
760 /* Make sure that at least one account is viewed if there are any
761 * accounts, for instance when adding the first account: */
762 set_at_least_one_account_visible (self);
766 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
768 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
769 gtk_scrolled_window_add_with_viewport
770 (GTK_SCROLLED_WINDOW(win), widget);
772 gtk_container_add (GTK_CONTAINER(win),
783 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
785 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
787 GList *oerrsignals = priv->queue_err_signals;
788 while (oerrsignals) {
789 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
790 g_signal_handler_disconnect (esignal->queue, esignal->signal);
791 g_slice_free (QueueErrorSignal, esignal);
792 oerrsignals = g_list_next (oerrsignals);
794 g_list_free (priv->queue_err_signals);
795 priv->queue_err_signals = NULL;
800 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
802 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
805 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
809 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
811 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
813 /* Update visibility */
816 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
820 modest_main_window_disconnect_signals (ModestWindow *self)
822 ModestMainWindowPrivate *priv;
823 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
825 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
826 priv->sighandlers = NULL;
830 connect_signals (ModestMainWindow *self)
832 ModestWindowPrivate *parent_priv;
833 ModestMainWindowPrivate *priv;
836 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
837 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
842 modest_signal_mgr_connect (priv->sighandlers,
843 G_OBJECT(priv->folder_view), "key-press-event",
844 G_CALLBACK(on_inner_widgets_key_pressed), self);
846 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "folder_selection_changed",
847 G_CALLBACK (modest_main_window_on_folder_selection_changed), self);
849 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
850 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), self);
852 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event",
853 G_CALLBACK (on_folder_view_focus_in), self);
855 /* Folder view CSM */
856 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
857 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
858 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
859 G_CALLBACK(_folder_view_csm_menu_activated),
863 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
864 G_CALLBACK(modest_ui_actions_on_header_selected), self);
866 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
867 G_CALLBACK(modest_ui_actions_on_header_activated), self);
869 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
870 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
872 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
873 G_CALLBACK(on_inner_widgets_key_pressed), self);
875 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
876 G_CALLBACK(on_msg_count_changed), self);
878 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
879 G_CALLBACK (on_header_view_focus_in), self);
881 modest_signal_mgr_connect (priv->sighandlers,
882 G_OBJECT (priv->header_view),
884 G_CALLBACK (on_updating_msg_list),
887 /* Header view CSM */
888 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
889 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
891 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
892 G_CALLBACK(_header_view_csm_menu_activated),
897 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
898 G_CALLBACK (modest_main_window_window_state_event),
901 /* Mail Operation Queue */
903 modest_signal_mgr_connect (priv->sighandlers,
904 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
906 G_CALLBACK (on_queue_changed), self);
908 /* Track changes in the device name */
910 modest_signal_mgr_connect (priv->sighandlers,
911 G_OBJECT(modest_runtime_get_conf ()),
913 G_CALLBACK (on_configuration_key_changed),
916 /* Track account changes. We need to refresh the toolbar */
918 modest_signal_mgr_connect (priv->sighandlers,
919 G_OBJECT (modest_runtime_get_account_store ()),
921 G_CALLBACK (on_account_inserted),
924 modest_signal_mgr_connect (priv->sighandlers,
925 G_OBJECT (modest_runtime_get_account_store ()),
927 G_CALLBACK (on_account_removed),
930 /* We need to refresh the send & receive menu to change the bold
931 * account when the default account changes. */
933 modest_signal_mgr_connect (priv->sighandlers,
934 G_OBJECT (modest_runtime_get_account_mgr ()),
935 "default_account_changed",
936 G_CALLBACK (on_default_account_changed),
941 modest_signal_mgr_connect (priv->sighandlers,
942 G_OBJECT (modest_runtime_get_account_store()),
943 "password_requested",
944 G_CALLBACK (modest_ui_actions_on_password_requested),
949 /** Idle handler, to send/receive at startup .*/
951 sync_accounts_cb (ModestMainWindow *win)
953 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
954 return FALSE; /* Do not call this idle handler again. */
959 on_hildon_program_is_topmost_notify(GObject *self,
960 GParamSpec *propert_param, gpointer user_data)
962 HildonProgram *app = HILDON_PROGRAM (self);
965 ModestWindow* self = MODEST_WINDOW(user_data);
968 /* Note that use of hildon_program_set_can_hibernate()
969 * is generally referred to as "setting the killable flag",
970 * though hibernation does not seem equal to death.
973 if (hildon_program_get_is_topmost (app)) {
974 /* Prevent hibernation when the progam comes to the foreground,
975 * because hibernation should only happen when the application
976 * is in the background: */
977 hildon_program_set_can_hibernate (app, FALSE);
979 /* Allow hibernation if the program has gone to the background: */
981 /* However, prevent hibernation while the settings are being changed: */
982 const gboolean hibernation_prevented =
983 modest_window_mgr_get_hibernation_is_prevented (
984 modest_runtime_get_window_mgr ());
986 if (hibernation_prevented)
987 hildon_program_set_can_hibernate (app, FALSE);
989 /* Allow hibernation, after saving the state: */
990 modest_osso_save_state();
991 hildon_program_set_can_hibernate (app, TRUE);
998 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1000 GtkWidget *folder_win = (GtkWidget *) user_data;
1001 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1003 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1004 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1005 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
1007 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1009 /* Connect signals */
1010 connect_signals (MODEST_MAIN_WINDOW (self));
1012 /* Set account store */
1013 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1014 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1016 /* Load previous osso state, for instance if we are being restored from
1018 modest_osso_load_state ();
1020 /* Restore window & widget settings */
1021 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1023 /* /\* The UI spec wants us to show a connection dialog when the application is */
1024 /* * started by the user, if there is no connection. */
1025 /* * Do this before showing the account wizard, */
1026 /* * because wizard needs a connection to discover capabilities. *\/ */
1027 /* modest_platform_connect_and_wait (GTK_WINDOW (self), NULL); */
1029 /* Check if accounts exist and show the account wizard if not */
1030 gboolean accounts_exist =
1031 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1033 if (!accounts_exist) {
1034 /* This is necessary to have the main window shown behind the dialog
1035 It's an ugly hack... jschmid */
1036 gtk_widget_show_all(GTK_WIDGET(self));
1037 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1040 GtkAction *send_receive_all;
1041 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1042 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1043 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1044 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1045 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1046 modest_account_mgr_free_account_names (accounts);
1051 modest_main_window_new (void)
1053 ModestMainWindow *self = NULL;
1054 ModestMainWindowPrivate *priv = NULL;
1055 ModestWindowPrivate *parent_priv = NULL;
1056 GtkWidget *folder_win = NULL;
1057 ModestDimmingRulesGroup *menu_rules_group = NULL;
1058 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1059 GtkActionGroup *action_group = NULL;
1060 GError *error = NULL;
1061 ModestConf *conf = NULL;
1062 GtkAction *action = NULL;
1063 GdkPixbuf *window_icon;
1065 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1066 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1067 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1069 parent_priv->ui_manager = gtk_ui_manager_new();
1070 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1072 action_group = gtk_action_group_new ("ModestMainWindowActions");
1073 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1075 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1076 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1078 /* Add common actions */
1079 gtk_action_group_add_actions (action_group,
1080 modest_action_entries,
1081 G_N_ELEMENTS (modest_action_entries),
1084 gtk_action_group_add_actions (action_group,
1085 modest_folder_view_action_entries,
1086 G_N_ELEMENTS (modest_folder_view_action_entries),
1089 gtk_action_group_add_actions (action_group,
1090 modest_header_view_action_entries,
1091 G_N_ELEMENTS (modest_header_view_action_entries),
1094 gtk_action_group_add_toggle_actions (action_group,
1095 modest_toggle_action_entries,
1096 G_N_ELEMENTS (modest_toggle_action_entries),
1099 gtk_action_group_add_toggle_actions (action_group,
1100 modest_main_window_toggle_action_entries,
1101 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1104 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1105 g_object_unref (action_group);
1107 /* Load the UI definition */
1108 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1109 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1110 if (error != NULL) {
1111 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1112 g_error_free (error);
1116 /* Add common dimming rules */
1117 modest_dimming_rules_group_add_rules (menu_rules_group,
1118 modest_main_window_menu_dimming_entries,
1119 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1120 MODEST_WINDOW (self));
1121 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1122 modest_main_window_toolbar_dimming_entries,
1123 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1124 MODEST_WINDOW (self));
1126 /* Insert dimming rules group for this window */
1127 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1128 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1129 g_object_unref (menu_rules_group);
1130 g_object_unref (toolbar_rules_group);
1132 /* Add accelerators */
1133 gtk_window_add_accel_group (GTK_WINDOW (self),
1134 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1136 /* Menubar. Update the state of some toggles */
1137 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1138 conf = modest_runtime_get_conf ();
1139 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1140 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1141 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1142 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1143 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1144 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1145 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1146 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1147 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1148 gtk_widget_show (parent_priv->menubar);
1150 /* Get device name */
1151 modest_maemo_utils_get_device_name ();
1155 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1156 if (!priv->header_view)
1157 g_printerr ("modest: cannot instantiate header view\n");
1158 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1159 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1160 MODEST_CONF_HEADER_VIEW_KEY);
1162 /* Other style properties of header view */
1163 g_object_set (G_OBJECT (priv->header_view),
1164 "rules-hint", FALSE,
1166 /* gtk_widget_show (priv->header_view); */
1169 priv->empty_view = create_empty_view ();
1170 gtk_widget_show (priv->empty_view);
1172 /* Create scrolled windows */
1173 folder_win = gtk_scrolled_window_new (NULL, NULL);
1174 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1175 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1177 GTK_POLICY_AUTOMATIC);
1178 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1180 GTK_POLICY_AUTOMATIC);
1181 /* gtk_widget_show (priv->contents_widget); */
1184 priv->main_paned = gtk_hpaned_new ();
1185 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1186 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1187 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1189 /* putting it all together... */
1190 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1191 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1192 gtk_widget_show (priv->main_vbox);
1194 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1196 HildonProgram *app = hildon_program_get_instance ();
1197 hildon_program_add_window (app, HILDON_WINDOW (self));
1199 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1200 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1202 g_signal_connect (G_OBJECT(self), "show",
1203 G_CALLBACK (modest_main_window_on_show), folder_win);
1205 /* Set window icon */
1206 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1208 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1209 g_object_unref (window_icon);
1212 /* Dont't restore settings here,
1213 * because it requires a gtk_widget_show(),
1214 * and we don't want to do that until later,
1215 * so that the UI is not visible for non-menu D-Bus activation.
1217 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1219 return MODEST_WINDOW(self);
1223 modest_main_window_close_all (ModestMainWindow *self)
1226 GtkResponseType response;
1228 /* Create the confirmation dialog MSG-NOT308 */
1229 note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
1230 _("emev_nc_close_windows"),
1231 _("mcen_bd_yes"), GTK_RESPONSE_YES,
1232 _("mcen_bd_no"), GTK_RESPONSE_NO,
1235 response = gtk_dialog_run (GTK_DIALOG (note));
1236 gtk_widget_destroy (GTK_WIDGET (note));
1238 if (response == GTK_RESPONSE_YES)
1246 modest_main_window_set_style (ModestMainWindow *self,
1247 ModestMainWindowStyle style)
1249 ModestMainWindowPrivate *priv;
1250 ModestWindowPrivate *parent_priv;
1254 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1256 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1257 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1259 /* no change -> nothing to do */
1260 if (priv->style == style)
1263 /* Get toggle button and update the state if needed. This will
1264 happen only when the set_style is not invoked from the UI,
1265 for example when it's called from widget memory */
1266 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1267 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1268 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1269 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1270 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1271 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1272 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1275 priv->style = style;
1277 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1278 /* Remove main paned */
1279 g_object_ref (priv->main_paned);
1280 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1282 /* Reparent the contents widget to the main vbox */
1283 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1286 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1287 /* Remove header view */
1288 g_object_ref (priv->contents_widget);
1289 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1291 /* Reparent the main paned */
1292 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1293 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1297 g_return_if_reached ();
1300 /* Let header view grab the focus if it's being shown */
1301 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1302 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1304 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1307 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1310 ModestMainWindowStyle
1311 modest_main_window_get_style (ModestMainWindow *self)
1313 ModestMainWindowPrivate *priv;
1315 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1317 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1324 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1326 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1327 ModestWindowPrivate *parent_priv;
1328 ModestWindowMgr *mgr;
1329 gboolean is_fullscreen;
1330 GtkAction *fs_toggle_action;
1333 mgr = modest_runtime_get_window_mgr ();
1335 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1337 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1339 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1340 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1341 if (is_fullscreen != active) {
1342 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1351 set_homogeneous (GtkWidget *widget,
1354 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1355 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1359 modest_main_window_show_toolbar (ModestWindow *self,
1360 gboolean show_toolbar)
1362 ModestMainWindowPrivate *priv = NULL;
1363 ModestWindowPrivate *parent_priv = NULL;
1364 GtkWidget *reply_button = NULL, *menu = NULL;
1365 GtkWidget *placeholder = NULL;
1367 const gchar *action_name;
1370 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1371 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1372 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1374 /* Set optimized view status */
1375 priv->optimized_view = !show_toolbar;
1377 if (!parent_priv->toolbar) {
1378 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1380 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1382 /* Set homogeneous toolbar */
1383 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1384 set_homogeneous, NULL);
1386 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1387 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1388 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1389 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1390 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1391 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1392 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1393 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1395 /* Add ProgressBar (Transfer toolbar) */
1396 priv->progress_bar = modest_progress_bar_widget_new ();
1397 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1398 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1399 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1400 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1401 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1403 /* Connect cancel 'clicked' signal to abort progress mode */
1404 g_signal_connect(priv->cancel_toolitem, "clicked",
1405 G_CALLBACK(cancel_progressbar),
1408 /* Add it to the observers list */
1409 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1412 hildon_window_add_toolbar (HILDON_WINDOW (self),
1413 GTK_TOOLBAR (parent_priv->toolbar));
1415 /* Set reply button tap and hold menu */
1416 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1417 "/ToolBar/ToolbarMessageReply");
1418 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1419 "/ToolbarReplyCSM");
1420 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1422 /* Set send & receive button tap and hold menu */
1423 update_menus (MODEST_MAIN_WINDOW (self));
1427 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1428 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1429 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1431 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1432 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1434 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1438 /* Update also the actions (to update the toggles in the
1439 menus), we have to do it manually because some other window
1440 of the same time could have changed it (remember that the
1441 toolbar fullscreen mode is shared by all the windows of the
1443 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1444 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1446 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1448 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1449 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1454 on_account_inserted (TnyAccountStore *accoust_store,
1455 TnyAccount *account,
1458 update_menus (MODEST_MAIN_WINDOW (user_data));
1462 on_default_account_changed (ModestAccountMgr* mgr,
1465 update_menus (MODEST_MAIN_WINDOW (user_data));
1469 on_account_removed (TnyAccountStore *accoust_store,
1470 TnyAccount *account,
1473 update_menus (MODEST_MAIN_WINDOW (user_data));
1477 * This function manages the key events used to navigate between
1478 * header and folder views (when the window is in split view)
1481 * -------------------------------------------------
1482 * HeaderView GDK_Left Move focus to folder view
1483 * FolderView GDK_Right Move focus to header view
1485 * There is no need to scroll to selected row, the widgets will be the
1486 * responsibles of doing that (probably managing the focus-in event
1489 on_inner_widgets_key_pressed (GtkWidget *widget,
1493 ModestMainWindowPrivate *priv;
1495 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1497 /* Do nothing if we're in SIMPLE style */
1498 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1501 if (MODEST_IS_HEADER_VIEW (widget)) {
1502 if (event->keyval == GDK_Left)
1503 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1504 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1505 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1506 if (selected_headers > 1) {
1507 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1511 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1512 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1518 set_alignment (GtkWidget *widget,
1521 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1522 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1526 create_empty_view (void)
1528 GtkLabel *label = NULL;
1529 GtkWidget *align = NULL;
1531 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1532 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1533 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1534 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1536 return GTK_WIDGET(align);
1540 * Free the returned string
1543 get_gray_color_markup (GtkWidget *styled_widget)
1545 gchar *gray_color_markup;
1547 /* Obtain the secondary text color. We need a realized widget, that's why
1548 we get styled_widget from outside */
1549 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1551 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1552 gray_color_markup = modest_text_utils_get_color_string (&color);
1554 gray_color_markup = g_strdup ("#BBBBBB");
1556 return gray_color_markup;
1560 * Free the returned string
1563 create_device_name_visual_string (const gchar *device_name,
1564 const gchar *gray_color_markup)
1568 /* We have to use "" to fill the %s of the translation. We can
1569 not just use the device name because the device name is
1570 shown in a different color, so it could not be included
1571 into the <span> tag */
1572 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1573 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1583 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1585 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1590 gchar *gray_color_markup;
1592 vbox = gtk_vbox_new (FALSE, 0);
1594 gray_color_markup = get_gray_color_markup (styled_widget);
1596 /* Account description: */
1597 if (modest_tny_account_is_virtual_local_folders (account)
1598 || (modest_tny_account_is_memory_card_account (account))) {
1600 /* Get device name */
1601 gchar *device_name = NULL;
1602 if (modest_tny_account_is_virtual_local_folders (account))
1603 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1604 MODEST_CONF_DEVICE_NAME, NULL);
1606 device_name = g_strdup (tny_account_get_name (account));
1608 label = create_device_name_visual_string ((const gchar *) device_name,
1609 (const gchar *) gray_color_markup);
1610 label_w = gtk_label_new (NULL);
1611 gtk_label_set_markup (GTK_LABEL (label_w), label);
1612 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1613 g_free (device_name);
1616 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1617 gtk_box_pack_start (GTK_BOX (vbox),
1618 gtk_label_new (tny_account_get_name (account)),
1621 /* Other accounts, such as IMAP and POP: */
1626 /* Put proto in uppercase */
1627 proto = g_string_new (tny_account_get_proto (account));
1628 proto = g_string_ascii_up (proto);
1630 /* note: mcen_fi_localroot_description is something like "%s account"
1631 * however, we should display "%s account: %s"... therefore, ugly tmp */
1632 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1633 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1634 gray_color_markup, tmp, tny_account_get_name (account));
1637 label_w = gtk_label_new (NULL);
1638 gtk_label_set_markup (GTK_LABEL (label_w), label);
1639 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1640 g_string_free (proto, TRUE);
1646 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1647 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1648 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1649 modest_tny_folder_store_get_message_count (folder_store));
1650 label_w = gtk_label_new (NULL);
1651 gtk_label_set_markup (GTK_LABEL (label_w), label);
1652 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1656 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1658 _("mcen_fi_rootfolder_folders"),
1659 modest_tny_folder_store_get_folder_count (folder_store));
1660 label_w = gtk_label_new (NULL);
1661 gtk_label_set_markup (GTK_LABEL (label_w), label);
1662 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1666 if (modest_tny_account_is_virtual_local_folders (account)
1667 || modest_tny_account_is_memory_card_account (account)) {
1669 gchar *size = modest_text_utils_get_display_size (
1670 modest_tny_folder_store_get_local_size (folder_store));
1672 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1673 gray_color_markup, _("mcen_fi_rootfolder_size"),
1677 label_w = gtk_label_new (NULL);
1678 gtk_label_set_markup (GTK_LABEL (label_w), label);
1679 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1681 } else if (TNY_IS_ACCOUNT(folder_store)) {
1682 TnyAccount *account = TNY_ACCOUNT(folder_store);
1684 time_t last_updated;
1685 gchar *last_updated_string;
1686 /* Get last updated from configuration */
1687 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1688 tny_account_get_id (account));
1690 if (last_updated > 0)
1691 last_updated_string = modest_text_utils_get_display_date(last_updated);
1693 last_updated_string = g_strdup (_("mcen_va_never"));
1695 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1696 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1697 label_w = gtk_label_new (NULL);
1698 gtk_label_set_markup (GTK_LABEL (label_w), label);
1699 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1700 g_free (last_updated_string);
1704 g_free (gray_color_markup);
1707 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1713 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1715 ModestMainWindowPrivate *priv = NULL;
1717 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1719 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1721 return priv->send_receive_in_progress;
1725 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1727 GtkAction *action = NULL;
1728 GtkWidget *widget = NULL;
1729 ModestMainWindowPrivate *priv = NULL;
1731 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1732 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1734 priv->send_receive_in_progress = TRUE;
1736 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1737 gtk_action_set_sensitive (action, FALSE);
1738 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1739 /* gtk_action_set_sensitive (action, FALSE); */
1740 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1741 gtk_widget_set_sensitive (widget, FALSE);
1745 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1747 GtkAction *action = NULL;
1748 GtkWidget *widget = NULL;
1749 ModestMainWindowPrivate *priv = NULL;
1751 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1752 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1754 priv->send_receive_in_progress = FALSE;
1756 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1757 gtk_action_set_sensitive (action, TRUE);
1758 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1759 /* gtk_action_set_sensitive (action, TRUE); */
1760 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1761 gtk_widget_set_sensitive (widget, TRUE);
1766 on_msg_count_changed (ModestHeaderView *header_view,
1768 TnyFolderChange *change,
1769 ModestMainWindow *main_window)
1771 gboolean folder_empty = FALSE;
1772 gboolean all_marked_as_deleted = FALSE;
1773 TnyFolderChangeChanged changed;
1774 ModestMainWindowPrivate *priv;
1776 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1777 g_return_if_fail (TNY_IS_FOLDER(folder));
1778 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1779 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1781 changed = tny_folder_change_get_changed (change);
1783 /* If something changes */
1784 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1785 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1787 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1789 /* Check header removed (hide marked as DELETED headers) */
1790 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1791 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1794 /* Check if all messages are marked to be deleted */
1795 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1796 folder_empty = folder_empty || all_marked_as_deleted ;
1798 /* Set contents style of headers view */
1800 modest_main_window_set_contents_style (main_window,
1801 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1802 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1805 modest_main_window_set_contents_style (main_window,
1806 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1812 modest_main_window_set_contents_style (ModestMainWindow *self,
1813 ModestMainWindowContentsStyle style)
1815 ModestMainWindowPrivate *priv;
1817 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1819 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1821 /* We allow to set the same content style than the previously
1822 set if there are details, because it could happen when we're
1823 selecting different accounts consecutively */
1824 if ((priv->contents_style == style) &&
1825 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1828 /* Remove previous child. Delete it if it was an account
1830 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1832 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1833 g_object_ref (content);
1834 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1835 g_object_ref (priv->empty_view);
1836 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1839 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1842 priv->contents_style = style;
1844 switch (priv->contents_style) {
1845 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1846 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1847 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1850 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1852 /* if we're started without main win, there may not be a folder
1853 * view. this fixes a GLib-Critical */
1854 if (priv->folder_view) {
1855 TnyFolderStore *selected_folderstore =
1856 modest_folder_view_get_selected (priv->folder_view);
1857 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1858 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1859 TNY_ACCOUNT (selected_folderstore));
1861 wrap_in_scrolled_window (priv->contents_widget,
1862 priv->details_widget);
1864 g_object_unref (selected_folderstore);
1865 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1870 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1871 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1872 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1876 g_return_if_reached ();
1880 gtk_widget_show_all (priv->contents_widget);
1883 ModestMainWindowContentsStyle
1884 modest_main_window_get_contents_style (ModestMainWindow *self)
1886 ModestMainWindowPrivate *priv;
1888 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1890 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1891 return priv->contents_style;
1896 on_configuration_key_changed (ModestConf* conf,
1898 ModestConfEvent event,
1899 ModestConfNotificationId id,
1900 ModestMainWindow *self)
1902 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1903 TnyAccount *account = NULL;
1905 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1908 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1911 if (priv->folder_view)
1912 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1914 if (account && TNY_IS_ACCOUNT (account) &&
1915 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1918 const gchar *device_name;
1919 gchar *new_text, *gray_color_markup;
1922 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1923 label = GTK_LABEL (children->data);
1925 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1926 MODEST_CONF_DEVICE_NAME, NULL);
1928 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1929 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1931 gtk_label_set_markup (label, new_text);
1932 gtk_widget_show (GTK_WIDGET (label));
1934 g_free (gray_color_markup);
1936 g_list_free (children);
1938 g_object_unref (account);
1942 set_toolbar_transfer_mode (ModestMainWindow *self)
1944 ModestMainWindowPrivate *priv = NULL;
1946 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1948 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1950 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1952 if (priv->progress_bar_timeout > 0) {
1953 g_source_remove (priv->progress_bar_timeout);
1954 priv->progress_bar_timeout = 0;
1961 set_toolbar_mode (ModestMainWindow *self,
1962 ModestToolBarModes mode)
1964 ModestWindowPrivate *parent_priv = NULL;
1965 ModestMainWindowPrivate *priv = NULL;
1966 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1968 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1970 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1971 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1973 /* In case this was called before the toolbar exists: */
1974 if (!(parent_priv->toolbar))
1977 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1979 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1980 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1981 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1983 /* Sets current toolbar mode */
1984 priv->current_toolbar_mode = mode;
1986 /* Checks the dimming rules */
1987 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1989 /* Show and hide toolbar items */
1991 case TOOLBAR_MODE_NORMAL:
1993 gtk_action_set_visible (sort_action, TRUE);
1995 gtk_action_set_visible (refresh_action, TRUE);
1996 if (priv->progress_toolitem) {
1997 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1998 gtk_widget_hide (priv->progress_toolitem);
2000 if (priv->progress_bar)
2001 gtk_widget_hide (priv->progress_bar);
2004 gtk_action_set_visible (cancel_action, FALSE);
2006 /* Hide toolbar if optimized view is enabled */
2007 if (priv->optimized_view)
2008 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2010 case TOOLBAR_MODE_TRANSFER:
2012 gtk_action_set_visible (sort_action, FALSE);
2014 gtk_action_set_visible (refresh_action, FALSE);
2016 gtk_action_set_visible (cancel_action, TRUE);
2017 if (priv->progress_toolitem) {
2018 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2019 gtk_widget_show (priv->progress_toolitem);
2021 if (priv->progress_bar)
2022 gtk_widget_show (priv->progress_bar);
2024 /* Show toolbar if it's hiden (optimized view ) */
2025 if (priv->optimized_view)
2026 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2029 g_return_if_reached ();
2034 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2036 ModestMainWindowPrivate *priv;
2038 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2039 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2041 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2045 cancel_progressbar (GtkToolButton *toolbutton,
2046 ModestMainWindow *self)
2049 ModestMainWindowPrivate *priv;
2051 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2053 /* Get operation observers and cancel all the operations */
2054 tmp = priv->progress_widgets;
2056 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2057 tmp=g_slist_next(tmp);
2062 observers_empty (ModestMainWindow *self)
2065 ModestMainWindowPrivate *priv;
2066 gboolean is_empty = TRUE;
2067 guint pending_ops = 0;
2069 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2070 tmp = priv->progress_widgets;
2072 /* Check all observers */
2073 while (tmp && is_empty) {
2074 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2075 is_empty = pending_ops == 0;
2077 tmp = g_slist_next(tmp);
2085 * Gets the toolbar mode needed for each mail operation. It stores in
2086 * @mode_changed if the toolbar mode has changed or not
2088 static ModestToolBarModes
2089 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2090 ModestMailOperation *mail_op,
2091 gboolean *mode_changed)
2093 ModestToolBarModes mode;
2094 ModestMainWindowPrivate *priv;
2096 *mode_changed = FALSE;
2097 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2099 /* Get toolbar mode from operation id*/
2100 switch (modest_mail_operation_get_type_operation (mail_op)) {
2101 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2102 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2103 mode = TOOLBAR_MODE_TRANSFER;
2104 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2105 *mode_changed = TRUE;
2108 mode = TOOLBAR_MODE_NORMAL;
2114 on_mail_operation_started (ModestMailOperation *mail_op,
2117 ModestMainWindow *self;
2118 ModestMailOperationTypeOperation op_type;
2119 ModestMainWindowPrivate *priv;
2120 ModestToolBarModes mode;
2122 gboolean mode_changed = FALSE;
2123 TnyAccount *account;
2125 self = MODEST_MAIN_WINDOW (user_data);
2126 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2128 /* Do not show progress for receiving operations if the
2129 account is the local account or the MMC one */
2130 op_type = modest_mail_operation_get_type_operation (mail_op);
2131 account = modest_mail_operation_get_account (mail_op);
2132 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2135 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2136 modest_tny_account_is_memory_card_account (account));
2137 g_object_unref (account);
2142 /* Get toolbar mode from operation id*/
2143 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2145 /* Add operation observers and change toolbar if neccessary*/
2146 tmp = priv->progress_widgets;
2147 if (mode == TOOLBAR_MODE_TRANSFER) {
2149 set_toolbar_transfer_mode(self);
2152 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2154 tmp = g_slist_next (tmp);
2160 on_mail_operation_finished (ModestMailOperation *mail_op,
2163 ModestToolBarModes mode;
2164 ModestMailOperationTypeOperation op_type;
2166 ModestMainWindow *self;
2167 gboolean mode_changed;
2168 TnyAccount *account;
2169 ModestMainWindowPrivate *priv;
2171 self = MODEST_MAIN_WINDOW (user_data);
2172 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2174 /* The mail operation was not added to the progress objects if
2175 the account was the local account or the MMC one */
2176 op_type = modest_mail_operation_get_type_operation (mail_op);
2177 account = modest_mail_operation_get_account (mail_op);
2178 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2181 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2182 modest_tny_account_is_memory_card_account (account));
2183 g_object_unref (account);
2188 /* Get toolbar mode from operation id*/
2189 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2191 /* Change toolbar mode */
2192 tmp = priv->progress_widgets;
2193 if (mode == TOOLBAR_MODE_TRANSFER) {
2195 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2197 tmp = g_slist_next (tmp);
2200 /* If no more operations are being observed, NORMAL mode is enabled again */
2201 if (observers_empty (self)) {
2202 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2208 on_queue_changed (ModestMailOperationQueue *queue,
2209 ModestMailOperation *mail_op,
2210 ModestMailOperationQueueNotification type,
2211 ModestMainWindow *self)
2213 ModestMainWindowPrivate *priv;
2215 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2217 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2218 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2220 "operation-started",
2221 G_CALLBACK (on_mail_operation_started),
2223 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2225 "operation-finished",
2226 G_CALLBACK (on_mail_operation_finished),
2228 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2229 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2231 "operation-started");
2232 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2234 "operation-finished");
2239 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2241 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2244 /* Get account data */
2245 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2246 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2248 /* Set the new visible & active account */
2249 if (acc_data && acc_data->store_account) {
2250 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2251 acc_data->store_account->account_name);
2252 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2253 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2254 if (action != NULL) {
2255 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2256 modest_maemo_toggle_action_set_active_block_notify (
2257 GTK_TOGGLE_ACTION (action),
2263 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2268 modest_account_mgr_free_account_data (mgr, acc_data);
2271 /* Make sure that at least one account is "viewed": */
2273 set_at_least_one_account_visible(ModestMainWindow *self)
2275 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2276 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2278 if (!(priv->folder_view)) {
2279 /* It is too early to do this. */
2283 const gchar *active_server_account_name =
2284 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2285 if (!active_server_account_name ||
2286 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2288 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2289 if (first_modest_name) {
2290 set_account_visible (self, first_modest_name);
2291 g_free (first_modest_name);
2297 on_show_account_action_toggled (GtkToggleAction *action,
2300 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2302 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2303 if (gtk_toggle_action_get_active (action))
2304 set_account_visible (self, acc_name);
2308 refresh_account (const gchar *account_name)
2312 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2314 /* If account_name == NULL, we must update all (option All) */
2316 modest_ui_actions_do_send_receive_all (win);
2318 modest_ui_actions_do_send_receive (account_name, win);
2323 on_refresh_account_action_activated (GtkAction *action,
2326 refresh_account ((const gchar*) user_data);
2330 on_send_receive_csm_activated (GtkMenuItem *item,
2333 refresh_account ((const gchar*) user_data);
2337 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2339 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2341 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2347 on_folder_view_focus_in (GtkWidget *widget,
2348 GdkEventFocus *event,
2351 ModestMainWindow *main_window = NULL;
2353 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2354 main_window = MODEST_MAIN_WINDOW (userdata);
2356 /* Update toolbar dimming state */
2357 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2363 on_header_view_focus_in (GtkWidget *widget,
2364 GdkEventFocus *event,
2367 ModestMainWindow *main_window = NULL;
2368 ModestMainWindowPrivate *priv = NULL;
2370 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2371 main_window = MODEST_MAIN_WINDOW (userdata);
2372 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2374 /* Update toolbar dimming state */
2375 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2381 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2382 TnyFolderStore *folder_store,
2384 ModestMainWindow *main_window)
2386 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2387 GtkAction *action = NULL;
2388 gboolean show_reply = TRUE;
2389 gboolean show_forward = TRUE;
2390 gboolean show_cancel_send = FALSE;
2391 gboolean show_clipboard = TRUE;
2392 gboolean show_delete = TRUE;
2395 if (TNY_IS_ACCOUNT (folder_store)) {
2396 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2397 } else if (TNY_IS_FOLDER (folder_store)) {
2398 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2399 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2400 TNY_FOLDER (folder_store));
2401 switch (folder_type) {
2402 case TNY_FOLDER_TYPE_DRAFTS:
2403 show_clipboard = show_delete = TRUE;
2404 show_reply = show_forward = show_cancel_send = FALSE;
2406 case TNY_FOLDER_TYPE_SENT:
2407 show_forward = show_clipboard = show_delete = TRUE;
2408 show_reply = show_cancel_send = FALSE;
2410 case TNY_FOLDER_TYPE_OUTBOX:
2411 show_clipboard = show_delete = show_cancel_send = TRUE;
2412 show_reply = show_forward = FALSE;
2415 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2416 show_cancel_send = FALSE;
2419 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2420 show_cancel_send = FALSE;
2425 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2426 gtk_action_set_visible (action, show_reply);
2427 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2428 gtk_action_set_visible (action, show_reply);
2429 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2430 gtk_action_set_visible (action, show_forward);
2431 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2432 gtk_action_set_visible (action, show_cancel_send);
2433 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2434 gtk_action_set_visible (action, show_delete);
2436 /* We finally call to the ui actions handler, after updating properly
2437 * the header view CSM */
2438 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2442 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2443 GtkTreeModel *model,
2444 GtkTreeRowReference *row_reference,
2445 ModestMainWindow *self)
2447 ModestMainWindowPrivate *priv = NULL;
2448 GtkTreeModel *header_model = NULL;
2449 GtkTreePath *path = NULL;
2451 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2452 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2453 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2455 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2456 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2458 /* Do nothing if we changed the folder in the main view */
2459 if (header_model != model)
2462 /* Select the message in the header view */
2463 path = gtk_tree_row_reference_get_path (row_reference);
2464 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2466 gtk_tree_path_free (path);
2472 show_updating_banner (gpointer user_data)
2474 ModestMainWindowPrivate *priv = NULL;
2476 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2478 priv->updating_banner =
2479 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2480 _CS ("ckdg_pb_updating"));
2482 /* Remove timeout */
2483 priv->updating_banner_timeout = 0;
2488 * We use this function to show/hide a progress banner showing
2489 * "Updating" while the header view is being filled. We're not showing
2490 * it unless the update takes more than 2 seconds
2492 * If starting = TRUE then the refresh is starting, otherwise it means
2493 * that is has just finished
2496 on_updating_msg_list (ModestHeaderView *header_view,
2500 ModestMainWindowPrivate *priv = NULL;
2502 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2504 /* Remove old timeout */
2505 if (priv->updating_banner_timeout > 0) {
2506 g_source_remove (priv->updating_banner_timeout);
2507 priv->updating_banner_timeout = 0;
2510 /* Create a new timeout */
2512 priv->updating_banner_timeout =
2513 g_timeout_add (2000, show_updating_banner, user_data);
2515 /* Remove the banner if exists */
2516 if (priv->updating_banner) {
2517 gtk_widget_destroy (priv->updating_banner);
2518 priv->updating_banner = NULL;