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_set_style (ModestMainWindow *self,
1224 ModestMainWindowStyle style)
1226 ModestMainWindowPrivate *priv;
1227 ModestWindowPrivate *parent_priv;
1231 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1233 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1234 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1236 /* no change -> nothing to do */
1237 if (priv->style == style)
1240 /* Get toggle button and update the state if needed. This will
1241 happen only when the set_style is not invoked from the UI,
1242 for example when it's called from widget memory */
1243 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1244 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1245 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1246 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1247 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1248 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1249 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1252 priv->style = style;
1254 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1255 /* Remove main paned */
1256 g_object_ref (priv->main_paned);
1257 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1259 /* Reparent the contents widget to the main vbox */
1260 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1263 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1264 /* Remove header view */
1265 g_object_ref (priv->contents_widget);
1266 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1268 /* Reparent the main paned */
1269 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1270 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1274 g_return_if_reached ();
1277 /* Let header view grab the focus if it's being shown */
1278 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1279 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1281 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1284 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1287 ModestMainWindowStyle
1288 modest_main_window_get_style (ModestMainWindow *self)
1290 ModestMainWindowPrivate *priv;
1292 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1294 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1301 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1303 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1304 ModestWindowPrivate *parent_priv;
1305 ModestWindowMgr *mgr;
1306 gboolean is_fullscreen;
1307 GtkAction *fs_toggle_action;
1310 mgr = modest_runtime_get_window_mgr ();
1312 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1314 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1316 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1317 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1318 if (is_fullscreen != active) {
1319 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1328 set_homogeneous (GtkWidget *widget,
1331 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1332 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1336 modest_main_window_show_toolbar (ModestWindow *self,
1337 gboolean show_toolbar)
1339 ModestMainWindowPrivate *priv = NULL;
1340 ModestWindowPrivate *parent_priv = NULL;
1341 GtkWidget *reply_button = NULL, *menu = NULL;
1342 GtkWidget *placeholder = NULL;
1344 const gchar *action_name;
1347 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1348 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1349 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1351 /* Set optimized view status */
1352 priv->optimized_view = !show_toolbar;
1354 if (!parent_priv->toolbar) {
1355 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1357 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1359 /* Set homogeneous toolbar */
1360 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1361 set_homogeneous, NULL);
1363 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1364 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1365 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1366 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1367 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1368 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1369 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1370 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1372 /* Add ProgressBar (Transfer toolbar) */
1373 priv->progress_bar = modest_progress_bar_widget_new ();
1374 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1375 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1376 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1377 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1378 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1380 /* Connect cancel 'clicked' signal to abort progress mode */
1381 g_signal_connect(priv->cancel_toolitem, "clicked",
1382 G_CALLBACK(cancel_progressbar),
1385 /* Add it to the observers list */
1386 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1389 hildon_window_add_toolbar (HILDON_WINDOW (self),
1390 GTK_TOOLBAR (parent_priv->toolbar));
1392 /* Set reply button tap and hold menu */
1393 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1394 "/ToolBar/ToolbarMessageReply");
1395 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1396 "/ToolbarReplyCSM");
1397 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1399 /* Set send & receive button tap and hold menu */
1400 update_menus (MODEST_MAIN_WINDOW (self));
1404 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1405 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1406 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1408 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1409 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1411 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1415 /* Update also the actions (to update the toggles in the
1416 menus), we have to do it manually because some other window
1417 of the same time could have changed it (remember that the
1418 toolbar fullscreen mode is shared by all the windows of the
1420 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1421 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1423 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1425 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1426 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1431 on_account_inserted (TnyAccountStore *accoust_store,
1432 TnyAccount *account,
1435 update_menus (MODEST_MAIN_WINDOW (user_data));
1439 on_default_account_changed (ModestAccountMgr* mgr,
1442 update_menus (MODEST_MAIN_WINDOW (user_data));
1446 on_account_removed (TnyAccountStore *accoust_store,
1447 TnyAccount *account,
1450 update_menus (MODEST_MAIN_WINDOW (user_data));
1454 * This function manages the key events used to navigate between
1455 * header and folder views (when the window is in split view)
1458 * -------------------------------------------------
1459 * HeaderView GDK_Left Move focus to folder view
1460 * FolderView GDK_Right Move focus to header view
1462 * There is no need to scroll to selected row, the widgets will be the
1463 * responsibles of doing that (probably managing the focus-in event
1466 on_inner_widgets_key_pressed (GtkWidget *widget,
1470 ModestMainWindowPrivate *priv;
1472 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1474 /* Do nothing if we're in SIMPLE style */
1475 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1478 if (MODEST_IS_HEADER_VIEW (widget)) {
1479 if (event->keyval == GDK_Left)
1480 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1481 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1482 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1483 if (selected_headers > 1) {
1484 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1488 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1489 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1495 set_alignment (GtkWidget *widget,
1498 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1499 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1503 create_empty_view (void)
1505 GtkLabel *label = NULL;
1506 GtkWidget *align = NULL;
1508 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1509 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1510 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1511 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1513 return GTK_WIDGET(align);
1517 * Free the returned string
1520 get_gray_color_markup (GtkWidget *styled_widget)
1522 gchar *gray_color_markup;
1524 /* Obtain the secondary text color. We need a realized widget, that's why
1525 we get styled_widget from outside */
1526 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1528 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1529 gray_color_markup = modest_text_utils_get_color_string (&color);
1531 gray_color_markup = g_strdup ("#BBBBBB");
1533 return gray_color_markup;
1537 * Free the returned string
1540 create_device_name_visual_string (const gchar *device_name,
1541 const gchar *gray_color_markup)
1545 /* We have to use "" to fill the %s of the translation. We can
1546 not just use the device name because the device name is
1547 shown in a different color, so it could not be included
1548 into the <span> tag */
1549 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1550 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1560 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1562 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1567 gchar *gray_color_markup;
1569 vbox = gtk_vbox_new (FALSE, 0);
1571 gray_color_markup = get_gray_color_markup (styled_widget);
1573 /* Account description: */
1574 if (modest_tny_account_is_virtual_local_folders (account)
1575 || (modest_tny_account_is_memory_card_account (account))) {
1577 /* Get device name */
1578 gchar *device_name = NULL;
1579 if (modest_tny_account_is_virtual_local_folders (account))
1580 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1581 MODEST_CONF_DEVICE_NAME, NULL);
1583 device_name = g_strdup (tny_account_get_name (account));
1585 label = create_device_name_visual_string ((const gchar *) device_name,
1586 (const gchar *) gray_color_markup);
1587 label_w = gtk_label_new (NULL);
1588 gtk_label_set_markup (GTK_LABEL (label_w), label);
1589 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1590 g_free (device_name);
1593 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1594 gtk_box_pack_start (GTK_BOX (vbox),
1595 gtk_label_new (tny_account_get_name (account)),
1598 /* Other accounts, such as IMAP and POP: */
1603 /* Put proto in uppercase */
1604 proto = g_string_new (tny_account_get_proto (account));
1605 proto = g_string_ascii_up (proto);
1607 /* note: mcen_fi_localroot_description is something like "%s account"
1608 * however, we should display "%s account: %s"... therefore, ugly tmp */
1609 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1610 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1611 gray_color_markup, tmp, tny_account_get_name (account));
1614 label_w = gtk_label_new (NULL);
1615 gtk_label_set_markup (GTK_LABEL (label_w), label);
1616 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1617 g_string_free (proto, TRUE);
1623 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1624 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1625 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1626 modest_tny_folder_store_get_message_count (folder_store));
1627 label_w = gtk_label_new (NULL);
1628 gtk_label_set_markup (GTK_LABEL (label_w), label);
1629 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1633 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1635 _("mcen_fi_rootfolder_folders"),
1636 modest_tny_folder_store_get_folder_count (folder_store));
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);
1643 if (modest_tny_account_is_virtual_local_folders (account)
1644 || modest_tny_account_is_memory_card_account (account)) {
1646 gchar *size = modest_text_utils_get_display_size (
1647 modest_tny_folder_store_get_local_size (folder_store));
1649 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1650 gray_color_markup, _("mcen_fi_rootfolder_size"),
1654 label_w = gtk_label_new (NULL);
1655 gtk_label_set_markup (GTK_LABEL (label_w), label);
1656 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1658 } else if (TNY_IS_ACCOUNT(folder_store)) {
1659 TnyAccount *account = TNY_ACCOUNT(folder_store);
1661 time_t last_updated;
1662 gchar *last_updated_string;
1663 /* Get last updated from configuration */
1664 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1665 tny_account_get_id (account));
1667 if (last_updated > 0)
1668 last_updated_string = modest_text_utils_get_display_date(last_updated);
1670 last_updated_string = g_strdup (_("mcen_va_never"));
1672 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1673 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1674 label_w = gtk_label_new (NULL);
1675 gtk_label_set_markup (GTK_LABEL (label_w), label);
1676 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1677 g_free (last_updated_string);
1681 g_free (gray_color_markup);
1684 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1690 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1692 ModestMainWindowPrivate *priv = NULL;
1694 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1696 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1698 return priv->send_receive_in_progress;
1702 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1704 GtkAction *action = NULL;
1705 GtkWidget *widget = NULL;
1706 ModestMainWindowPrivate *priv = NULL;
1708 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1709 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1711 priv->send_receive_in_progress = TRUE;
1713 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1714 gtk_action_set_sensitive (action, FALSE);
1715 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1716 /* gtk_action_set_sensitive (action, FALSE); */
1717 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1718 gtk_widget_set_sensitive (widget, FALSE);
1722 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1724 GtkAction *action = NULL;
1725 GtkWidget *widget = NULL;
1726 ModestMainWindowPrivate *priv = NULL;
1728 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1729 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1731 priv->send_receive_in_progress = FALSE;
1733 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1734 gtk_action_set_sensitive (action, TRUE);
1735 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1736 /* gtk_action_set_sensitive (action, TRUE); */
1737 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1738 gtk_widget_set_sensitive (widget, TRUE);
1743 on_msg_count_changed (ModestHeaderView *header_view,
1745 TnyFolderChange *change,
1746 ModestMainWindow *main_window)
1748 gboolean folder_empty = FALSE;
1749 gboolean all_marked_as_deleted = FALSE;
1750 TnyFolderChangeChanged changed;
1751 ModestMainWindowPrivate *priv;
1753 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1754 g_return_if_fail (TNY_IS_FOLDER(folder));
1755 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1756 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1758 changed = tny_folder_change_get_changed (change);
1760 /* If something changes */
1761 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1762 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1764 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1766 /* Check header removed (hide marked as DELETED headers) */
1767 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1768 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1771 /* Check if all messages are marked to be deleted */
1772 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1773 folder_empty = folder_empty || all_marked_as_deleted ;
1775 /* Set contents style of headers view */
1777 modest_main_window_set_contents_style (main_window,
1778 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1779 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1782 modest_main_window_set_contents_style (main_window,
1783 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1789 modest_main_window_set_contents_style (ModestMainWindow *self,
1790 ModestMainWindowContentsStyle style)
1792 ModestMainWindowPrivate *priv;
1794 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1796 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1798 /* We allow to set the same content style than the previously
1799 set if there are details, because it could happen when we're
1800 selecting different accounts consecutively */
1801 if ((priv->contents_style == style) &&
1802 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1805 /* Remove previous child. Delete it if it was an account
1807 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1809 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1810 g_object_ref (content);
1811 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1812 g_object_ref (priv->empty_view);
1813 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1816 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1819 priv->contents_style = style;
1821 switch (priv->contents_style) {
1822 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1823 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1824 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1827 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1829 /* if we're started without main win, there may not be a folder
1830 * view. this fixes a GLib-Critical */
1831 if (priv->folder_view) {
1832 TnyFolderStore *selected_folderstore =
1833 modest_folder_view_get_selected (priv->folder_view);
1834 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1835 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1836 TNY_ACCOUNT (selected_folderstore));
1838 wrap_in_scrolled_window (priv->contents_widget,
1839 priv->details_widget);
1841 g_object_unref (selected_folderstore);
1842 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1847 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1848 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1849 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1853 g_return_if_reached ();
1857 gtk_widget_show_all (priv->contents_widget);
1860 ModestMainWindowContentsStyle
1861 modest_main_window_get_contents_style (ModestMainWindow *self)
1863 ModestMainWindowPrivate *priv;
1865 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1867 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1868 return priv->contents_style;
1873 on_configuration_key_changed (ModestConf* conf,
1875 ModestConfEvent event,
1876 ModestConfNotificationId id,
1877 ModestMainWindow *self)
1879 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1880 TnyAccount *account = NULL;
1882 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1885 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1888 if (priv->folder_view)
1889 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1891 if (account && TNY_IS_ACCOUNT (account) &&
1892 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1895 const gchar *device_name;
1896 gchar *new_text, *gray_color_markup;
1899 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1900 label = GTK_LABEL (children->data);
1902 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1903 MODEST_CONF_DEVICE_NAME, NULL);
1905 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1906 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1908 gtk_label_set_markup (label, new_text);
1909 gtk_widget_show (GTK_WIDGET (label));
1911 g_free (gray_color_markup);
1913 g_list_free (children);
1915 g_object_unref (account);
1919 set_toolbar_transfer_mode (ModestMainWindow *self)
1921 ModestMainWindowPrivate *priv = NULL;
1923 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1925 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1927 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1929 if (priv->progress_bar_timeout > 0) {
1930 g_source_remove (priv->progress_bar_timeout);
1931 priv->progress_bar_timeout = 0;
1938 set_toolbar_mode (ModestMainWindow *self,
1939 ModestToolBarModes mode)
1941 ModestWindowPrivate *parent_priv = NULL;
1942 ModestMainWindowPrivate *priv = NULL;
1943 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1945 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1947 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1948 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1950 /* In case this was called before the toolbar exists: */
1951 if (!(parent_priv->toolbar))
1954 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1956 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1957 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1958 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1960 /* Sets current toolbar mode */
1961 priv->current_toolbar_mode = mode;
1963 /* Checks the dimming rules */
1964 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1966 /* Show and hide toolbar items */
1968 case TOOLBAR_MODE_NORMAL:
1970 gtk_action_set_visible (sort_action, TRUE);
1972 gtk_action_set_visible (refresh_action, TRUE);
1973 if (priv->progress_toolitem) {
1974 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1975 gtk_widget_hide (priv->progress_toolitem);
1977 if (priv->progress_bar)
1978 gtk_widget_hide (priv->progress_bar);
1981 gtk_action_set_visible (cancel_action, FALSE);
1983 /* Hide toolbar if optimized view is enabled */
1984 if (priv->optimized_view)
1985 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1987 case TOOLBAR_MODE_TRANSFER:
1989 gtk_action_set_visible (sort_action, FALSE);
1991 gtk_action_set_visible (refresh_action, FALSE);
1993 gtk_action_set_visible (cancel_action, TRUE);
1994 if (priv->progress_toolitem) {
1995 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1996 gtk_widget_show (priv->progress_toolitem);
1998 if (priv->progress_bar)
1999 gtk_widget_show (priv->progress_bar);
2001 /* Show toolbar if it's hiden (optimized view ) */
2002 if (priv->optimized_view)
2003 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2006 g_return_if_reached ();
2011 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2013 ModestMainWindowPrivate *priv;
2015 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2016 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2018 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2022 cancel_progressbar (GtkToolButton *toolbutton,
2023 ModestMainWindow *self)
2026 ModestMainWindowPrivate *priv;
2028 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2030 /* Get operation observers and cancel all the operations */
2031 tmp = priv->progress_widgets;
2033 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2034 tmp=g_slist_next(tmp);
2039 observers_empty (ModestMainWindow *self)
2042 ModestMainWindowPrivate *priv;
2043 gboolean is_empty = TRUE;
2044 guint pending_ops = 0;
2046 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2047 tmp = priv->progress_widgets;
2049 /* Check all observers */
2050 while (tmp && is_empty) {
2051 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2052 is_empty = pending_ops == 0;
2054 tmp = g_slist_next(tmp);
2062 * Gets the toolbar mode needed for each mail operation. It stores in
2063 * @mode_changed if the toolbar mode has changed or not
2065 static ModestToolBarModes
2066 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2067 ModestMailOperation *mail_op,
2068 gboolean *mode_changed)
2070 ModestToolBarModes mode;
2071 ModestMainWindowPrivate *priv;
2073 *mode_changed = FALSE;
2074 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2076 /* Get toolbar mode from operation id*/
2077 switch (modest_mail_operation_get_type_operation (mail_op)) {
2078 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2079 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2080 mode = TOOLBAR_MODE_TRANSFER;
2081 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2082 *mode_changed = TRUE;
2085 mode = TOOLBAR_MODE_NORMAL;
2091 on_mail_operation_started (ModestMailOperation *mail_op,
2094 ModestMainWindow *self;
2095 ModestMailOperationTypeOperation op_type;
2096 ModestMainWindowPrivate *priv;
2097 ModestToolBarModes mode;
2099 gboolean mode_changed = FALSE;
2100 TnyAccount *account;
2102 self = MODEST_MAIN_WINDOW (user_data);
2103 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2105 /* Do not show progress for receiving operations if the
2106 account is the local account or the MMC one */
2107 op_type = modest_mail_operation_get_type_operation (mail_op);
2108 account = modest_mail_operation_get_account (mail_op);
2109 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2112 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2113 modest_tny_account_is_memory_card_account (account));
2114 g_object_unref (account);
2119 /* Get toolbar mode from operation id*/
2120 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2122 /* Add operation observers and change toolbar if neccessary*/
2123 tmp = priv->progress_widgets;
2124 if (mode == TOOLBAR_MODE_TRANSFER) {
2126 set_toolbar_transfer_mode(self);
2129 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2131 tmp = g_slist_next (tmp);
2137 on_mail_operation_finished (ModestMailOperation *mail_op,
2140 ModestToolBarModes mode;
2141 ModestMailOperationTypeOperation op_type;
2143 ModestMainWindow *self;
2144 gboolean mode_changed;
2145 TnyAccount *account;
2146 ModestMainWindowPrivate *priv;
2148 self = MODEST_MAIN_WINDOW (user_data);
2149 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2151 /* The mail operation was not added to the progress objects if
2152 the account was the local account or the MMC one */
2153 op_type = modest_mail_operation_get_type_operation (mail_op);
2154 account = modest_mail_operation_get_account (mail_op);
2155 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2158 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2159 modest_tny_account_is_memory_card_account (account));
2160 g_object_unref (account);
2165 /* Get toolbar mode from operation id*/
2166 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2168 /* Change toolbar mode */
2169 tmp = priv->progress_widgets;
2170 if (mode == TOOLBAR_MODE_TRANSFER) {
2172 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2174 tmp = g_slist_next (tmp);
2177 /* If no more operations are being observed, NORMAL mode is enabled again */
2178 if (observers_empty (self)) {
2179 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2185 on_queue_changed (ModestMailOperationQueue *queue,
2186 ModestMailOperation *mail_op,
2187 ModestMailOperationQueueNotification type,
2188 ModestMainWindow *self)
2190 ModestMainWindowPrivate *priv;
2192 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2194 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2195 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2197 "operation-started",
2198 G_CALLBACK (on_mail_operation_started),
2200 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2202 "operation-finished",
2203 G_CALLBACK (on_mail_operation_finished),
2205 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2206 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2208 "operation-started");
2209 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2211 "operation-finished");
2216 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2218 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2221 /* Get account data */
2222 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2223 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2225 /* Set the new visible & active account */
2226 if (acc_data && acc_data->store_account) {
2227 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2228 acc_data->store_account->account_name);
2229 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2230 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2231 if (action != NULL) {
2232 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2233 modest_maemo_toggle_action_set_active_block_notify (
2234 GTK_TOGGLE_ACTION (action),
2240 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2245 modest_account_mgr_free_account_data (mgr, acc_data);
2248 /* Make sure that at least one account is "viewed": */
2250 set_at_least_one_account_visible(ModestMainWindow *self)
2252 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2253 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2255 if (!(priv->folder_view)) {
2256 /* It is too early to do this. */
2260 const gchar *active_server_account_name =
2261 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2262 if (!active_server_account_name ||
2263 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2265 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2266 if (first_modest_name) {
2267 set_account_visible (self, first_modest_name);
2268 g_free (first_modest_name);
2274 on_show_account_action_toggled (GtkToggleAction *action,
2277 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2279 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2280 if (gtk_toggle_action_get_active (action))
2281 set_account_visible (self, acc_name);
2285 refresh_account (const gchar *account_name)
2289 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2291 /* If account_name == NULL, we must update all (option All) */
2293 modest_ui_actions_do_send_receive_all (win);
2295 modest_ui_actions_do_send_receive (account_name, win);
2300 on_refresh_account_action_activated (GtkAction *action,
2303 refresh_account ((const gchar*) user_data);
2307 on_send_receive_csm_activated (GtkMenuItem *item,
2310 refresh_account ((const gchar*) user_data);
2314 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2316 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2318 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2324 on_folder_view_focus_in (GtkWidget *widget,
2325 GdkEventFocus *event,
2328 ModestMainWindow *main_window = NULL;
2330 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2331 main_window = MODEST_MAIN_WINDOW (userdata);
2333 /* Update toolbar dimming state */
2334 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2340 on_header_view_focus_in (GtkWidget *widget,
2341 GdkEventFocus *event,
2344 ModestMainWindow *main_window = NULL;
2345 ModestMainWindowPrivate *priv = NULL;
2347 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2348 main_window = MODEST_MAIN_WINDOW (userdata);
2349 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2351 /* Update toolbar dimming state */
2352 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2358 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2359 TnyFolderStore *folder_store,
2361 ModestMainWindow *main_window)
2363 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2364 GtkAction *action = NULL;
2365 gboolean show_reply = TRUE;
2366 gboolean show_forward = TRUE;
2367 gboolean show_cancel_send = FALSE;
2368 gboolean show_clipboard = TRUE;
2369 gboolean show_delete = TRUE;
2372 if (TNY_IS_ACCOUNT (folder_store)) {
2373 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2374 } else if (TNY_IS_FOLDER (folder_store)) {
2375 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2376 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2377 TNY_FOLDER (folder_store));
2378 switch (folder_type) {
2379 case TNY_FOLDER_TYPE_DRAFTS:
2380 show_clipboard = show_delete = TRUE;
2381 show_reply = show_forward = show_cancel_send = FALSE;
2383 case TNY_FOLDER_TYPE_SENT:
2384 show_forward = show_clipboard = show_delete = TRUE;
2385 show_reply = show_cancel_send = FALSE;
2387 case TNY_FOLDER_TYPE_OUTBOX:
2388 show_clipboard = show_delete = show_cancel_send = TRUE;
2389 show_reply = show_forward = FALSE;
2391 case TNY_FOLDER_TYPE_INVALID:
2392 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2395 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2396 show_cancel_send = FALSE;
2399 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2400 show_cancel_send = FALSE;
2405 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2406 gtk_action_set_visible (action, show_reply);
2407 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2408 gtk_action_set_visible (action, show_reply);
2409 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2410 gtk_action_set_visible (action, show_forward);
2411 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2412 gtk_action_set_visible (action, show_cancel_send);
2413 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2414 gtk_action_set_visible (action, show_delete);
2416 /* We finally call to the ui actions handler, after updating properly
2417 * the header view CSM */
2418 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2422 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2423 GtkTreeModel *model,
2424 GtkTreeRowReference *row_reference,
2425 ModestMainWindow *self)
2427 ModestMainWindowPrivate *priv = NULL;
2428 GtkTreeModel *header_model = NULL;
2429 GtkTreePath *path = NULL;
2431 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2432 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2433 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2435 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2436 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2438 /* Do nothing if we changed the folder in the main view */
2439 if (header_model != model)
2442 /* Select the message in the header view */
2443 path = gtk_tree_row_reference_get_path (row_reference);
2444 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2446 gtk_tree_path_free (path);
2452 show_updating_banner (gpointer user_data)
2454 ModestMainWindowPrivate *priv = NULL;
2456 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2458 priv->updating_banner =
2459 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2460 _CS ("ckdg_pb_updating"));
2462 /* Remove timeout */
2463 priv->updating_banner_timeout = 0;
2468 * We use this function to show/hide a progress banner showing
2469 * "Updating" while the header view is being filled. We're not showing
2470 * it unless the update takes more than 2 seconds
2472 * If starting = TRUE then the refresh is starting, otherwise it means
2473 * that is has just finished
2476 on_updating_msg_list (ModestHeaderView *header_view,
2480 ModestMainWindowPrivate *priv = NULL;
2482 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2484 /* Remove old timeout */
2485 if (priv->updating_banner_timeout > 0) {
2486 g_source_remove (priv->updating_banner_timeout);
2487 priv->updating_banner_timeout = 0;
2490 /* Create a new timeout */
2492 priv->updating_banner_timeout =
2493 g_timeout_add (2000, show_updating_banner, user_data);
2495 /* Remove the banner if exists */
2496 if (priv->updating_banner) {
2497 gtk_widget_destroy (priv->updating_banner);
2498 priv->updating_banner = NULL;