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);
100 update_menus (ModestMainWindow* self);
102 static void modest_main_window_show_toolbar (ModestWindow *window,
103 gboolean show_toolbar);
105 static void cancel_progressbar (GtkToolButton *toolbutton,
106 ModestMainWindow *self);
108 static void on_queue_changed (ModestMailOperationQueue *queue,
109 ModestMailOperation *mail_op,
110 ModestMailOperationQueueNotification type,
111 ModestMainWindow *self);
113 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
116 on_account_inserted (TnyAccountStore *accoust_store,
121 on_account_removed (TnyAccountStore *accoust_store,
126 on_account_changed (ModestAccountMgr* mgr,
127 const gchar* account,
130 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
134 static void on_configuration_key_changed (ModestConf* conf,
136 ModestConfEvent event,
137 ModestConfNotificationId id,
138 ModestMainWindow *self);
140 static void set_toolbar_mode (ModestMainWindow *self,
141 ModestToolBarModes mode);
143 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
145 static void on_show_account_action_activated (GtkAction *action,
148 static void on_refresh_account_action_activated (GtkAction *action,
151 static void on_send_receive_csm_activated (GtkMenuItem *item,
155 _on_msg_count_changed (ModestHeaderView *header_view,
157 TnyFolderChange *change,
158 ModestMainWindow *main_window);
161 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
164 static GtkWidget * create_empty_view (void);
167 on_folder_view_focus_in (GtkWidget *widget,
168 GdkEventFocus *event,
171 on_header_view_focus_in (GtkWidget *widget,
172 GdkEventFocus *event,
175 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
176 TnyFolderStore *folder_store,
178 ModestMainWindow *main_window);
181 set_at_least_one_account_visible(ModestMainWindow *self);
184 /* list my signals */
191 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
192 struct _ModestMainWindowPrivate {
193 GtkWidget *msg_paned;
194 GtkWidget *main_paned;
195 GtkWidget *main_vbox;
196 GtkWidget *contents_widget;
197 GtkWidget *empty_view;
199 /* Progress observers */
200 GtkWidget *progress_bar;
201 GSList *progress_widgets;
204 GtkWidget *progress_toolitem;
205 GtkWidget *cancel_toolitem;
206 GtkWidget *sort_toolitem;
207 GtkWidget *refresh_toolitem;
208 ModestToolBarModes current_toolbar_mode;
210 /* Merge ids used to add/remove accounts to the ViewMenu*/
211 GByteArray *merge_ids;
213 /* On-demand widgets */
214 GtkWidget *accounts_popup;
215 GtkWidget *details_widget;
217 /* Optimized view enabled */
218 gboolean optimized_view;
220 /* Optimized view enabled */
221 gboolean send_receive_in_progress;
223 ModestHeaderView *header_view;
224 ModestFolderView *folder_view;
226 ModestMainWindowStyle style;
227 ModestMainWindowContentsStyle contents_style;
229 guint progress_bar_timeout;
231 /* Signal handler UIDs */
232 GList *queue_err_signals;
235 ModestConfNotificationId notification_id;
237 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
238 MODEST_TYPE_MAIN_WINDOW, \
239 ModestMainWindowPrivate))
241 typedef struct _GetMsgAsyncHelper {
242 ModestMainWindowPrivate *main_window_private;
244 ModestTnyMsgReplyType reply_type;
245 ModestTnyMsgForwardType forward_type;
252 static GtkWindowClass *parent_class = NULL;
255 /* Private actions */
256 /* This is the context sensitive menu: */
257 static const GtkActionEntry modest_folder_view_action_entries [] = {
259 /* Folder View CSM actions */
260 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
261 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
262 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
263 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
264 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
265 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
268 static const GtkActionEntry modest_header_view_action_entries [] = {
270 /* Header View CSM actions */
271 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
272 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
273 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
274 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
275 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
276 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
277 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
278 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
279 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
280 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
283 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
284 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
287 /************************************************************************/
290 modest_main_window_get_type (void)
292 static GType my_type = 0;
294 static const GTypeInfo my_info = {
295 sizeof(ModestMainWindowClass),
296 NULL, /* base init */
297 NULL, /* base finalize */
298 (GClassInitFunc) modest_main_window_class_init,
299 NULL, /* class finalize */
300 NULL, /* class data */
301 sizeof(ModestMainWindow),
303 (GInstanceInitFunc) modest_main_window_init,
306 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
314 modest_main_window_class_init (ModestMainWindowClass *klass)
316 GObjectClass *gobject_class;
317 gobject_class = (GObjectClass*) klass;
318 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
320 parent_class = g_type_class_peek_parent (klass);
321 gobject_class->finalize = modest_main_window_finalize;
323 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
325 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
326 modest_window_class->save_state_func = save_state;
327 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
328 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
329 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
333 modest_main_window_init (ModestMainWindow *obj)
335 ModestMainWindowPrivate *priv;
337 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
339 priv->queue_err_signals = NULL;
340 priv->msg_paned = NULL;
341 priv->main_paned = NULL;
342 priv->main_vbox = NULL;
343 priv->header_view = NULL;
344 priv->folder_view = NULL;
345 priv->contents_widget = NULL;
346 priv->accounts_popup = NULL;
347 priv->details_widget = NULL;
348 priv->empty_view = NULL;
349 priv->progress_widgets = NULL;
350 priv->progress_bar = NULL;
351 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
352 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
353 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
354 priv->merge_ids = NULL;
355 priv->optimized_view = FALSE;
356 priv->send_receive_in_progress = FALSE;
357 priv->progress_bar_timeout = 0;
358 priv->sighandlers = NULL;
362 modest_main_window_finalize (GObject *obj)
364 ModestMainWindowPrivate *priv;
366 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
368 if (priv->notification_id) {
369 modest_conf_forget_namespace (modest_runtime_get_conf (),
370 MODEST_CONF_NAMESPACE,
371 priv->notification_id);
374 /* Sanity check: shouldn't be needed, the window mgr should
375 call this function before */
376 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
378 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
380 g_slist_free (priv->progress_widgets);
382 g_byte_array_free (priv->merge_ids, TRUE);
384 if (priv->progress_bar_timeout > 0) {
385 g_source_remove (priv->progress_bar_timeout);
386 priv->progress_bar_timeout = 0;
389 G_OBJECT_CLASS(parent_class)->finalize (obj);
393 modest_main_window_get_child_widget (ModestMainWindow *self,
394 ModestWidgetType widget_type)
396 ModestMainWindowPrivate *priv;
399 g_return_val_if_fail (self, NULL);
400 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
403 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
405 switch (widget_type) {
406 case MODEST_WIDGET_TYPE_HEADER_VIEW:
407 widget = (GtkWidget*)priv->header_view; break;
408 case MODEST_WIDGET_TYPE_FOLDER_VIEW:
409 widget = (GtkWidget*)priv->folder_view; break;
414 return widget ? GTK_WIDGET(widget) : NULL;
419 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
422 ModestMainWindowPrivate *priv;
424 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
426 conf = modest_runtime_get_conf ();
428 modest_widget_memory_restore (conf, G_OBJECT(self),
429 MODEST_CONF_MAIN_WINDOW_KEY);
431 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
432 MODEST_CONF_HEADER_VIEW_KEY);
434 if (do_folder_view_too)
435 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
436 MODEST_CONF_FOLDER_VIEW_KEY);
438 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
439 MODEST_CONF_MAIN_PANED_KEY);
441 /* We need to force a redraw here in order to get the right
442 position of the horizontal paned separator */
443 gtk_widget_show (GTK_WIDGET (self));
448 save_state (ModestWindow *window)
451 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
452 ModestMainWindowPrivate *priv;
454 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
455 conf = modest_runtime_get_conf ();
457 modest_widget_memory_save (conf,G_OBJECT(self),
458 MODEST_CONF_MAIN_WINDOW_KEY);
459 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
460 MODEST_CONF_MAIN_PANED_KEY);
461 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
462 // MODEST_CONF_HEADER_VIEW_KEY);
463 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
464 MODEST_CONF_FOLDER_VIEW_KEY);
468 compare_display_names (ModestAccountData *a,
469 ModestAccountData *b)
471 return strcmp (a->display_name, b->display_name);
475 update_menus (ModestMainWindow* self)
477 GSList *account_names, *iter, *accounts;
478 ModestMainWindowPrivate *priv;
479 ModestWindowPrivate *parent_priv;
480 ModestAccountMgr *mgr;
481 gint i, num_accounts;
482 GtkActionGroup *action_group;
484 gchar *default_account;
485 GtkWidget *send_receive_button, *item;
486 GtkAction *send_receive_all = NULL;
488 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
489 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
491 /* Get enabled account IDs */
492 mgr = modest_runtime_get_account_mgr ();
493 account_names = modest_account_mgr_account_names (mgr, TRUE);
494 iter = account_names;
498 ModestAccountData *account_data =
499 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
500 accounts = g_slist_prepend (accounts, account_data);
504 modest_account_mgr_free_account_names (account_names);
505 account_names = NULL;
507 /* Order the list of accounts by its display name */
508 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
509 num_accounts = g_slist_length (accounts);
511 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
512 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
513 gtk_action_set_visible (send_receive_all, num_accounts > 1);
515 /* Delete old send&receive popup items. We can not just do a
516 menu_detach because it does not work well with
518 if (priv->accounts_popup)
519 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
520 (GtkCallback) gtk_widget_destroy, NULL);
522 /* Delete old entries in the View menu. Do not free groups, it
524 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
526 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
527 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
528 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
529 GTK_ACTION_GROUP (groups->data));
532 if (priv->merge_ids) {
533 for (i = 0; i < priv->merge_ids->len; i++)
534 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
535 g_byte_array_free (priv->merge_ids, TRUE);
537 /* We need to call this in order to ensure
538 that the new actions are added in the right
539 order (alphabetical */
540 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
542 groups = g_list_next (groups);
544 priv->merge_ids = g_byte_array_sized_new (num_accounts);
546 /* Get send receive button */
547 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
548 "/ToolBar/ToolbarSendReceive");
550 /* Create the menu */
551 if (num_accounts > 1) {
552 if (!priv->accounts_popup)
553 priv->accounts_popup = gtk_menu_new ();
554 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
555 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
556 g_signal_connect (G_OBJECT (item),
558 G_CALLBACK (on_send_receive_csm_activated),
560 item = gtk_separator_menu_item_new ();
561 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
564 /* Create a new action group */
565 default_account = modest_account_mgr_get_default_account (mgr);
566 action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
567 for (i = 0; i < num_accounts; i++) {
568 gchar *display_name = NULL;
570 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
572 /* Create display name. The UI specification specifies a different format string
573 * to use for the default account, though both seem to be "%s", so
574 * I don't see what the point is. murrayc. */
575 if (default_account && account_data->account_name &&
576 !(strcmp (default_account, account_data->account_name) == 0)) {
577 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
578 account_data->display_name);
581 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
582 account_data->display_name);
585 /* Create action and add it to the action group. The
586 action name must be the account name, this way we
587 could know in the handlers the account to show */
588 if(account_data && account_data->account_name) {
589 gchar* item_name, *refresh_action_name;
591 GtkAction *view_account_action, *refresh_account_action;
593 view_account_action = gtk_action_new (account_data->account_name,
594 display_name, NULL, NULL);
595 gtk_action_group_add_action (action_group, view_account_action);
597 /* Add ui from account data. We allow 2^9-1 account
598 changes in a single execution because we're
599 downcasting the guint to a guint8 in order to use a
600 GByteArray. It should be enough. */
601 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
602 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
603 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
604 gtk_ui_manager_add_ui (parent_priv->ui_manager,
606 "/MenuBar/ViewMenu/ViewMenuAdditions",
608 account_data->account_name,
609 GTK_UI_MANAGER_MENUITEM,
612 /* Connect the action signal "activate" */
613 g_signal_connect (G_OBJECT (view_account_action),
615 G_CALLBACK (on_show_account_action_activated),
618 /* Create the items for the Tools->Send&Receive submenu */
619 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
620 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
621 display_name, NULL, NULL);
622 printf("DEBUG: %s: menu display_name=%s\n", __FUNCTION__, display_name);
623 gtk_action_group_add_action (action_group, refresh_account_action);
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/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
632 GTK_UI_MANAGER_MENUITEM,
634 g_free (refresh_action_name);
636 g_signal_connect_data (G_OBJECT (refresh_account_action),
638 G_CALLBACK (on_refresh_account_action_activated),
639 g_strdup (account_data->account_name),
640 (GClosureNotify) g_free,
643 /* Create item and add it to the send&receive
644 CSM. If there is only one account then
646 if (priv->accounts_popup) {
647 GtkWidget *label = gtk_label_new(NULL);
648 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
649 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
651 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
652 gtk_label_set_markup (GTK_LABEL (label), escaped);
657 gtk_label_set_text (GTK_LABEL (label), display_name);
660 item = gtk_menu_item_new ();
661 gtk_container_add (GTK_CONTAINER (item), label);
663 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
664 g_signal_connect_data (G_OBJECT (item),
666 G_CALLBACK (on_send_receive_csm_activated),
667 g_strdup (account_data->account_name),
668 (GClosureNotify) g_free,
675 g_free (display_name);
678 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
680 /* We cannot do this in the loop above because this relies on the action
681 * group being inserted. This makes the default account appear in bold.
682 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
683 for (i = 0; i < num_accounts; i++) {
684 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
686 if(account_data->account_name && default_account &&
687 strcmp (account_data->account_name, default_account) == 0) {
688 gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
690 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
691 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
695 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
696 if (GTK_IS_LABEL (child)) {
697 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
698 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
699 gtk_label_set_markup (GTK_LABEL (child), bold_name);
704 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
705 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
709 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
710 if (GTK_IS_LABEL (child)) {
711 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
712 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
713 gtk_label_set_markup (GTK_LABEL (child), bold_name);
721 modest_account_mgr_free_account_data (mgr, account_data);
724 if (priv->accounts_popup) {
725 /* Mandatory in order to view the menu contents */
726 gtk_widget_show_all (priv->accounts_popup);
728 /* Setup tap_and_hold just if was not done before*/
729 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
730 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
734 g_slist_free (accounts);
735 g_free (default_account);
738 /* Make sure that at least one account is viewed if there are any
739 * accounts, for instance when adding the first account: */
740 set_at_least_one_account_visible (self);
744 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
746 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
747 gtk_scrolled_window_add_with_viewport
748 (GTK_SCROLLED_WINDOW(win), widget);
750 gtk_container_add (GTK_CONTAINER(win),
755 /* static gboolean */
756 /* on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMainWindow *self) */
758 /* modest_window_save_state (MODEST_WINDOW(self)); */
763 /* on_sendqueue_error_happened (TnySendQueue *self, TnyHeader *header, TnyMsg *msg, GError *err, ModestMainWindow *user_data) */
766 /* printf ("DEBUG: %s: err->code=%d, err->message=%s\n", __FUNCTION__, err->code, err->message); */
768 /* if (err->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL) */
769 /* /\* Don't show waste the user's time by showing him a dialog telling him */
770 /* * that he has just cancelled something: *\/ */
774 /* /\* Get the server name: *\/ */
775 /* const gchar* server_name = NULL; */
777 /* TnyCamelTransportAccount* server_account = tny_camel_send_queue_get_transport_account ( */
778 /* TNY_CAMEL_SEND_QUEUE (self)); */
779 /* if (server_account) { */
780 /* server_name = tny_account_get_hostname (TNY_ACCOUNT (server_account)); */
782 /* g_object_unref (server_account); */
783 /* server_account = NULL; */
786 /* if (!server_name) */
787 /* server_name = _("Unknown Server"); */
789 /* /\* Show the appropriate message text for the GError: *\/ */
790 /* gchar *message = NULL; */
792 /* switch (err->code) { */
793 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_HOST_LOOKUP_FAILED: */
794 /* message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name); */
796 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_SERVICE_UNAVAILABLE: */
797 /* message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name); */
799 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_AUTHENTICATION_NOT_SUPPORTED: */
800 /* /\* TODO: This logical ID seems more suitable for a wrong username or password than for a */
801 /* * wrong authentication method. The user is unlikely to guess at the real cause. */
803 /* message = g_strdup_printf (_("eemev_ni_ui_smtp_authentication_fail_error"), server_name); */
805 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND: */
806 /* /\* TODO: Tinymail is still sending this sometimes when it should */
807 /* * send TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL. *\/ */
809 /* message = g_strdup (_("emev_ib_ui_smtp_send_error")); */
813 /* message = g_strdup (_("emev_ib_ui_smtp_send_error")); */
816 /* modest_maemo_show_information_note_and_forget (GTK_WINDOW (user_data), message); */
817 /* g_free (message); */
819 /* /\* TODO: Offer to remove the message, to avoid messages in future? *\/ */
821 /* TnyFolder *outbox = tny_send_queue_get_outbox (queue); */
822 /* tny_folder_remove_msg (outbox, header, NULL); */
823 /* tny_folder_sync (outbox, TRUE, NULL); */
824 /* g_object_unref (outbox); */
834 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
836 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
838 GList *oerrsignals = priv->queue_err_signals;
839 while (oerrsignals) {
840 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
841 g_signal_handler_disconnect (esignal->queue, esignal->signal);
842 g_slice_free (QueueErrorSignal, esignal);
843 oerrsignals = g_list_next (oerrsignals);
845 g_list_free (priv->queue_err_signals);
846 priv->queue_err_signals = NULL;
850 /* on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self) */
852 /* ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self); */
854 /* /\* When going online, do the equivalent of pressing the send/receive button, */
855 /* * as per the specification: */
856 /* * (without the check for >0 accounts, though that is not specified): *\/ */
858 /* TnyDevice *device = tny_account_store_get_device (store); */
860 /* /\* modest_folder_view_update_model (MODEST_FOLDER_VIEW (priv->folder_view), store); *\/ */
862 /* /\* Check that we are really online. */
863 /* * This signal should not be emitted when we are not connected, */
864 /* * but it seems to happen sometimes: *\/ */
865 /* if (!tny_device_is_online (device)) */
868 /* const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device)); */
869 /* printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id); */
871 /* /\* Stop the existing send queues: *\/ */
872 /* modest_runtime_remove_all_send_queues (); */
874 /* /\* Create the send queues again, using the appropriate transport accounts */
875 /* * for this new connection. */
876 /* * This could be the first time that they are created if this is the first */
877 /* * connection. *\/ */
878 /* /\* TODO: Does this really destroy the TnySendQueues and their threads */
879 /* * We do not want 2 TnySendQueues to exist with the same underlying */
880 /* * outbox directory. *\/ */
882 /* modest_main_window_cleanup_queue_error_signals (self); */
884 /* GSList *account_names = modest_account_mgr_account_names ( */
885 /* modest_runtime_get_account_mgr(), */
886 /* TRUE /\* enabled accounts only *\/); */
887 /* GSList *iter = account_names; */
889 /* const gchar *account_name = (const gchar*)(iter->data); */
890 /* if (account_name) { */
891 /* TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT ( */
892 /* modest_tny_account_store_get_transport_account_for_open_connection */
893 /* (modest_runtime_get_account_store(), account_name)); */
895 /* /\* Q: Is this the first location where the send-queues are requested? *\/ */
896 /* QueueErrorSignal *esignal = g_slice_new (QueueErrorSignal); */
897 /* printf ("debug: %s:\n Transport account for %s: %s\n", __FUNCTION__, account_name, */
898 /* tny_account_get_id(TNY_ACCOUNT(account))); */
899 /* esignal->queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (account)); */
900 /* esignal->signal = g_signal_connect (G_OBJECT (esignal->queue), "error-happened", */
901 /* G_CALLBACK (on_sendqueue_error_happened), self); */
902 /* priv->queue_err_signals = g_list_prepend (priv->queue_err_signals, esignal); */
906 /* iter = g_slist_next (iter); */
909 /* modest_account_mgr_free_account_names (account_names); */
910 /* account_names = NULL; */
912 /* modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self)); */
916 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
918 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
921 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
925 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
927 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
929 /* Update visibility */
932 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
936 modest_main_window_disconnect_signals (ModestWindow *self)
938 ModestMainWindowPrivate *priv;
939 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
941 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
942 priv->sighandlers = NULL;
946 connect_signals (ModestMainWindow *self)
948 ModestWindowPrivate *parent_priv;
949 ModestMainWindowPrivate *priv;
952 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
953 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
957 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
958 G_OBJECT(priv->folder_view), "key-press-event",
959 G_CALLBACK(on_inner_widgets_key_pressed), self);
960 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder_selection_changed",
961 G_CALLBACK(modest_main_window_on_folder_selection_changed), self);
962 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
963 G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
964 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event",
965 G_CALLBACK (on_folder_view_focus_in), self);
967 /* Folder view CSM */
968 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
969 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
970 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
971 G_CALLBACK(_folder_view_csm_menu_activated),
974 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
975 G_CALLBACK(modest_ui_actions_on_header_selected), self);
976 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
977 G_CALLBACK(modest_ui_actions_on_header_activated), self);
978 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
979 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
980 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
981 G_CALLBACK(on_inner_widgets_key_pressed), self);
982 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
983 G_CALLBACK(_on_msg_count_changed), self);
984 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
985 G_CALLBACK (on_header_view_focus_in), self);
987 /* Header view CSM */
988 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
989 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
990 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
991 G_CALLBACK(_header_view_csm_menu_activated),
995 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
996 G_CALLBACK (modest_main_window_window_state_event),
999 /* Mail Operation Queue */
1000 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_mail_operation_queue ()),
1001 "queue-changed", G_CALLBACK (on_queue_changed), self);
1003 /* Track changes in the device name */
1004 priv->notification_id = modest_conf_listen_to_namespace (modest_runtime_get_conf (),
1005 MODEST_CONF_NAMESPACE);
1006 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(modest_runtime_get_conf ()),
1007 "key_changed", G_CALLBACK (on_configuration_key_changed),
1010 /* Track account changes. We need to refresh the toolbar */
1011 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store ()),
1012 "account_inserted", G_CALLBACK (on_account_inserted),
1014 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store ()),
1015 "account_removed", G_CALLBACK (on_account_removed),
1018 /* We need to refresh the send & receive menu to change the bold
1019 * account when the default account changes. */
1020 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_mgr ()),
1021 "account_changed", G_CALLBACK (on_account_changed),
1025 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store()),
1026 "password_requested",
1027 G_CALLBACK (modest_ui_actions_on_password_requested), self);
1031 /** Idle handler, to send/receive at startup .*/
1033 sync_accounts_cb (ModestMainWindow *win)
1035 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
1036 return FALSE; /* Do not call this idle handler again. */
1040 static void on_hildon_program_is_topmost_notify(GObject *self,
1041 GParamSpec *propert_param, gpointer user_data)
1043 HildonProgram *app = HILDON_PROGRAM (self);
1046 ModestWindow* self = MODEST_WINDOW(user_data);
1049 /* Note that use of hildon_program_set_can_hibernate()
1050 * is generally referred to as "setting the killable flag",
1051 * though hibernation does not seem equal to death.
1054 if (hildon_program_get_is_topmost (app)) {
1055 /* Prevent hibernation when the progam comes to the foreground,
1056 * because hibernation should only happen when the application
1057 * is in the background: */
1058 hildon_program_set_can_hibernate (app, FALSE);
1060 /* Allow hibernation if the program has gone to the background: */
1062 /* However, prevent hibernation while the settings are being changed: */
1063 const gboolean hibernation_prevented =
1064 modest_window_mgr_get_hibernation_is_prevented (
1065 modest_runtime_get_window_mgr ());
1067 if (hibernation_prevented)
1068 hildon_program_set_can_hibernate (app, FALSE);
1070 /* Allow hibernation, after saving the state: */
1071 modest_osso_save_state();
1072 hildon_program_set_can_hibernate (app, TRUE);
1079 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1081 GtkWidget *folder_win = (GtkWidget *) user_data;
1082 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1084 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1085 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1086 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
1088 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1090 /* Connect signals */
1091 connect_signals ((ModestMainWindow*)self);
1093 /* Set account store */
1094 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1095 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1097 /* Load previous osso state, for instance if we are being restored from
1099 modest_osso_load_state ();
1101 /* Restore window & widget settings */
1103 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1105 /* The UI spec wants us to show a connection dialog when the application is
1106 * started by the user, if there is no connection.
1107 * Do this before showing the account wizard,
1108 * because wizard needs a connection to discover capabilities. */
1109 modest_platform_connect_and_wait (GTK_WINDOW (self), NULL);
1111 /* Check if accounts exist and show the account wizard if not */
1112 gboolean accounts_exist =
1113 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1115 if (!accounts_exist) {
1116 /* This is necessary to have the main window shown behind the dialog
1117 It's an ugly hack... jschmid */
1118 gtk_widget_show_all(GTK_WIDGET(self));
1119 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1122 GtkAction *send_receive_all;
1123 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1124 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1125 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1126 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1127 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1128 modest_account_mgr_free_account_names (accounts);
1133 modest_main_window_new (void)
1135 ModestMainWindow *self = NULL;
1136 ModestMainWindowPrivate *priv = NULL;
1137 ModestWindowPrivate *parent_priv = NULL;
1138 GtkWidget *folder_win = NULL;
1139 ModestDimmingRulesGroup *menu_rules_group = NULL;
1140 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1141 GtkActionGroup *action_group = NULL;
1142 GError *error = NULL;
1143 ModestConf *conf = NULL;
1144 GtkAction *action = NULL;
1145 GdkPixbuf *window_icon;
1147 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1148 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1149 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1151 parent_priv->ui_manager = gtk_ui_manager_new();
1152 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1154 action_group = gtk_action_group_new ("ModestMainWindowActions");
1155 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1157 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1158 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1160 /* Add common actions */
1161 gtk_action_group_add_actions (action_group,
1162 modest_action_entries,
1163 G_N_ELEMENTS (modest_action_entries),
1166 gtk_action_group_add_actions (action_group,
1167 modest_folder_view_action_entries,
1168 G_N_ELEMENTS (modest_folder_view_action_entries),
1171 gtk_action_group_add_actions (action_group,
1172 modest_header_view_action_entries,
1173 G_N_ELEMENTS (modest_header_view_action_entries),
1176 gtk_action_group_add_toggle_actions (action_group,
1177 modest_toggle_action_entries,
1178 G_N_ELEMENTS (modest_toggle_action_entries),
1181 gtk_action_group_add_toggle_actions (action_group,
1182 modest_main_window_toggle_action_entries,
1183 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1186 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1187 g_object_unref (action_group);
1189 /* Load the UI definition */
1190 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1191 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1192 if (error != NULL) {
1193 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1194 g_error_free (error);
1198 /* Add common dimming rules */
1199 modest_dimming_rules_group_add_rules (menu_rules_group,
1200 modest_main_window_menu_dimming_entries,
1201 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1203 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1204 modest_main_window_toolbar_dimming_entries,
1205 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1208 /* Insert dimming rules group for this window */
1209 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1210 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1211 g_object_unref (menu_rules_group);
1212 g_object_unref (toolbar_rules_group);
1214 /* Add accelerators */
1215 gtk_window_add_accel_group (GTK_WINDOW (self),
1216 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1218 /* Menubar. Update the state of some toggles */
1219 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1220 conf = modest_runtime_get_conf ();
1221 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1222 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1223 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1224 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
1225 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1226 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1227 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1228 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
1229 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1230 gtk_widget_show (parent_priv->menubar);
1232 /* Get device name */
1233 modest_maemo_utils_get_device_name ();
1237 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1238 if (!priv->header_view)
1239 g_printerr ("modest: cannot instantiate header view\n");
1240 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1241 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1242 MODEST_CONF_HEADER_VIEW_KEY);
1244 /* Other style properties of header view */
1245 g_object_set (G_OBJECT (priv->header_view),
1246 "rules-hint", FALSE,
1248 /* gtk_widget_show (priv->header_view); */
1251 priv->empty_view = create_empty_view ();
1252 gtk_widget_show (priv->empty_view);
1254 /* Create scrolled windows */
1255 folder_win = gtk_scrolled_window_new (NULL, NULL);
1256 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1257 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1259 GTK_POLICY_AUTOMATIC);
1260 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1262 GTK_POLICY_AUTOMATIC);
1263 /* gtk_widget_show (priv->contents_widget); */
1266 priv->main_paned = gtk_hpaned_new ();
1267 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1268 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1269 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1271 /* putting it all together... */
1272 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1273 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1274 gtk_widget_show (priv->main_vbox);
1276 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1278 HildonProgram *app = hildon_program_get_instance ();
1279 hildon_program_add_window (app, HILDON_WINDOW (self));
1281 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1282 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1284 g_signal_connect (G_OBJECT(self), "show",
1285 G_CALLBACK (modest_main_window_on_show), folder_win);
1287 /* Set window icon */
1288 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1290 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1291 g_object_unref (window_icon);
1294 /* Dont't restore settings here,
1295 * because it requires a gtk_widget_show(),
1296 * and we don't want to do that until later,
1297 * so that the UI is not visible for non-menu D-Bus activation.
1299 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1301 return MODEST_WINDOW(self);
1305 modest_main_window_close_all (ModestMainWindow *self)
1308 GtkResponseType response;
1310 /* Create the confirmation dialog MSG-NOT308 */
1311 note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
1312 _("emev_nc_close_windows"),
1313 _("mcen_bd_yes"), GTK_RESPONSE_YES,
1314 _("mcen_bd_no"), GTK_RESPONSE_NO,
1317 response = gtk_dialog_run (GTK_DIALOG (note));
1318 gtk_widget_destroy (GTK_WIDGET (note));
1320 if (response == GTK_RESPONSE_YES)
1328 modest_main_window_set_style (ModestMainWindow *self,
1329 ModestMainWindowStyle style)
1331 ModestMainWindowPrivate *priv;
1332 ModestWindowPrivate *parent_priv;
1336 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1338 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1339 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1341 /* no change -> nothing to do */
1342 if (priv->style == style)
1345 /* Get toggle button and update the state if needed. This will
1346 happen only when the set_style is not invoked from the UI,
1347 for example when it's called from widget memory */
1348 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1349 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1350 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1351 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1352 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1353 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1354 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1357 priv->style = style;
1359 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1360 /* Remove main paned */
1361 g_object_ref (priv->main_paned);
1362 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1364 /* Reparent the contents widget to the main vbox */
1365 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1367 if (modest_header_view_has_selected_headers (MODEST_HEADER_VIEW (priv->header_view))) {
1368 TnyList *selection = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (priv->header_view));
1369 TnyIterator *iterator = tny_list_create_iterator (selection);
1371 tny_iterator_first (iterator);
1372 header = TNY_HEADER (tny_iterator_get_current (iterator));
1373 if (tny_header_get_subject (header))
1374 gtk_window_set_title (GTK_WINDOW(self), tny_header_get_subject (header));
1376 gtk_window_set_title (GTK_WINDOW (self), _("mail_va_no_subject"));
1379 g_object_unref (header);
1381 g_object_unref (iterator);
1382 g_object_unref (selection);
1386 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1387 /* Remove header view */
1388 g_object_ref (priv->contents_widget);
1389 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1391 /* Reparent the main paned */
1392 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1393 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1397 g_return_if_reached ();
1400 /* Let header view grab the focus if it's being shown */
1401 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1402 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1404 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1407 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1410 ModestMainWindowStyle
1411 modest_main_window_get_style (ModestMainWindow *self)
1413 ModestMainWindowPrivate *priv;
1415 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1417 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1424 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1426 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1427 ModestWindowPrivate *parent_priv;
1428 ModestWindowMgr *mgr;
1429 gboolean is_fullscreen;
1430 GtkAction *fs_toggle_action;
1433 mgr = modest_runtime_get_window_mgr ();
1435 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1437 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1439 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1440 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1441 if (is_fullscreen != active) {
1442 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1451 set_homogeneous (GtkWidget *widget,
1454 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1455 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1459 modest_main_window_show_toolbar (ModestWindow *self,
1460 gboolean show_toolbar)
1462 ModestMainWindowPrivate *priv = NULL;
1463 ModestWindowPrivate *parent_priv = NULL;
1464 GtkWidget *reply_button = NULL, *menu = NULL;
1465 GtkWidget *placeholder = NULL;
1468 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1469 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1470 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1472 /* Set optimized view status */
1473 priv->optimized_view = !show_toolbar;
1475 if (!parent_priv->toolbar) {
1476 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1479 /* Set homogeneous toolbar */
1480 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1481 set_homogeneous, NULL);
1483 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1484 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1485 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1486 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1487 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1488 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1489 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1490 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1492 /* Add ProgressBar (Transfer toolbar) */
1493 priv->progress_bar = modest_progress_bar_widget_new ();
1494 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1495 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1496 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1497 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1498 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1500 /* Connect cancel 'clicked' signal to abort progress mode */
1501 g_signal_connect(priv->cancel_toolitem, "clicked",
1502 G_CALLBACK(cancel_progressbar),
1505 /* Add it to the observers list */
1506 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1509 hildon_window_add_toolbar (HILDON_WINDOW (self),
1510 GTK_TOOLBAR (parent_priv->toolbar));
1512 /* Set reply button tap and hold menu */
1513 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1514 "/ToolBar/ToolbarMessageReply");
1515 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1516 "/ToolbarReplyCSM");
1517 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1519 /* Set send & receive button tap and hold menu */
1520 update_menus (MODEST_MAIN_WINDOW (self));
1524 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1525 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1526 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1528 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1529 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1531 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1536 on_account_inserted (TnyAccountStore *accoust_store,
1537 TnyAccount *account,
1540 update_menus (MODEST_MAIN_WINDOW (user_data));
1544 on_account_changed (ModestAccountMgr* mgr,
1545 const gchar* account,
1548 gchar *default_account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
1550 /* Actually, we only want to know when another account has become
1551 * the default account, but there is no default_account_changed
1552 * signal in ModestAccountMgr. */
1553 if(strcmp(account, default_account) == 0)
1554 update_menus (MODEST_MAIN_WINDOW (user_data));
1556 g_free (default_account);
1560 on_account_removed (TnyAccountStore *accoust_store,
1561 TnyAccount *account,
1564 update_menus (MODEST_MAIN_WINDOW (user_data));
1568 * This function manages the key events used to navigate between
1569 * header and folder views (when the window is in split view)
1572 * -------------------------------------------------
1573 * HeaderView GDK_Left Move focus to folder view
1574 * FolderView GDK_Right Move focus to header view
1576 * There is no need to scroll to selected row, the widgets will be the
1577 * responsibles of doing that (probably managing the focus-in event
1580 on_inner_widgets_key_pressed (GtkWidget *widget,
1584 ModestMainWindowPrivate *priv;
1586 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1588 /* Do nothing if we're in SIMPLE style */
1589 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1592 if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1593 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1594 else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1595 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1601 set_alignment (GtkWidget *widget,
1604 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1605 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1609 create_empty_view (void)
1611 GtkLabel *label = NULL;
1612 GtkWidget *align = NULL;
1614 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1615 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1616 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1617 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1619 return GTK_WIDGET(align);
1623 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1625 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1630 gchar *gray_color_markup;
1632 vbox = gtk_vbox_new (FALSE, 0);
1634 /* Obtain the secondary text color. We need a realized widget, that's why
1635 we get styled_widget from outside */
1636 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1638 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1639 gray_color_markup = modest_text_utils_get_color_string (&color);
1641 // gray_color_markup is freed below
1642 gray_color_markup = g_strdup ("#BBBBBB");
1644 /* Account description: */
1646 if (modest_tny_account_is_virtual_local_folders (account)
1647 || (modest_tny_account_is_memory_card_account (account))) {
1649 /* Local folders: */
1651 /* Get device name */
1652 gchar *device_name = NULL;
1653 if (modest_tny_account_is_virtual_local_folders (account))
1654 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1655 MODEST_CONF_DEVICE_NAME, NULL);
1657 device_name = g_strdup (tny_account_get_name (account));
1659 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), ""); //TODO: Why the ""?
1660 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1661 gray_color_markup, tmp, device_name);
1663 label_w = gtk_label_new (NULL);
1664 gtk_label_set_markup (GTK_LABEL (label_w), label);
1665 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1666 g_free (device_name);
1669 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1670 gtk_box_pack_start (GTK_BOX (vbox),
1671 gtk_label_new (tny_account_get_name (account)),
1674 /* Other accounts, such as IMAP and POP: */
1679 /* Put proto in uppercase */
1680 proto = g_string_new (tny_account_get_proto (account));
1681 proto = g_string_ascii_up (proto);
1683 /* note: mcen_fi_localroot_description is something like "%s account"
1684 * however, we should display "%s account: %s"... therefore, ugly tmp */
1685 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1686 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1687 gray_color_markup, tmp, tny_account_get_name (account));
1690 label_w = gtk_label_new (NULL);
1691 gtk_label_set_markup (GTK_LABEL (label_w), label);
1692 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1693 g_string_free (proto, TRUE);
1699 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1700 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1701 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1702 modest_tny_folder_store_get_message_count (folder_store));
1703 label_w = gtk_label_new (NULL);
1704 gtk_label_set_markup (GTK_LABEL (label_w), label);
1705 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1709 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1711 _("mcen_fi_rootfolder_folders"),
1712 modest_tny_folder_store_get_folder_count (folder_store));
1713 label_w = gtk_label_new (NULL);
1714 gtk_label_set_markup (GTK_LABEL (label_w), label);
1715 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1719 if (modest_tny_account_is_virtual_local_folders (account)
1720 || modest_tny_account_is_memory_card_account (account)) {
1722 gchar *size = modest_text_utils_get_display_size (
1723 modest_tny_folder_store_get_local_size (folder_store));
1725 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1726 gray_color_markup, _("mcen_fi_rootfolder_size"),
1730 label_w = gtk_label_new (NULL);
1731 gtk_label_set_markup (GTK_LABEL (label_w), label);
1732 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1734 } else if (TNY_IS_ACCOUNT(folder_store)) {
1735 TnyAccount *account = TNY_ACCOUNT(folder_store);
1737 time_t last_updated;
1738 gchar *last_updated_string;
1739 /* Get last updated from configuration */
1740 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (),
1741 tny_account_get_id (account),
1742 MODEST_ACCOUNT_LAST_UPDATED,
1744 if (last_updated > 0)
1745 last_updated_string = modest_text_utils_get_display_date(last_updated);
1747 last_updated_string = g_strdup (_("mcen_va_never"));
1749 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1750 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1751 label_w = gtk_label_new (NULL);
1752 gtk_label_set_markup (GTK_LABEL (label_w), label);
1753 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1754 g_free (last_updated_string);
1758 g_free (gray_color_markup);
1761 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1767 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1769 ModestMainWindowPrivate *priv = NULL;
1771 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1773 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1775 return priv->send_receive_in_progress;
1779 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1781 GtkAction *action = NULL;
1782 GtkWidget *widget = NULL;
1783 ModestMainWindowPrivate *priv = NULL;
1785 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1786 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1788 priv->send_receive_in_progress = TRUE;
1790 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1791 gtk_action_set_sensitive (action, FALSE);
1792 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1793 /* gtk_action_set_sensitive (action, FALSE); */
1794 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1795 gtk_widget_set_sensitive (widget, FALSE);
1799 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1801 GtkAction *action = NULL;
1802 GtkWidget *widget = NULL;
1803 ModestMainWindowPrivate *priv = NULL;
1805 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1806 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1808 priv->send_receive_in_progress = FALSE;
1810 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1811 gtk_action_set_sensitive (action, TRUE);
1812 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1813 /* gtk_action_set_sensitive (action, TRUE); */
1814 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1815 gtk_widget_set_sensitive (widget, TRUE);
1820 _on_msg_count_changed (ModestHeaderView *header_view,
1822 TnyFolderChange *change,
1823 ModestMainWindow *main_window)
1825 printf ("DEBUG: %s\n", __FUNCTION__);
1826 gboolean folder_empty = FALSE;
1827 gboolean all_marked_as_deleted = FALSE;
1828 TnyFolderChangeChanged changed;
1829 ModestMainWindowPrivate *priv;
1831 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1832 g_return_if_fail (TNY_IS_FOLDER(folder));
1833 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1834 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1836 changed = tny_folder_change_get_changed (change);
1838 /* If something changes */
1839 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1840 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1842 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1844 printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1846 /* Check header removed (hide marked as DELETED headers) */
1847 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1848 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1851 /* Check if all messages are marked to be deleted */
1852 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1853 folder_empty = folder_empty || all_marked_as_deleted ;
1855 /* Set contents style of headers view */
1857 modest_main_window_set_contents_style (main_window,
1858 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1859 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1862 modest_main_window_set_contents_style (main_window,
1863 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1869 modest_main_window_set_contents_style (ModestMainWindow *self,
1870 ModestMainWindowContentsStyle style)
1872 ModestMainWindowPrivate *priv;
1874 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1876 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1878 /* We allow to set the same content style than the previously
1879 set if there are details, because it could happen when we're
1880 selecting different accounts consecutively */
1881 if ((priv->contents_style == style) &&
1882 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1885 /* Remove previous child. Delete it if it was an account
1887 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1889 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1890 g_object_ref (content);
1891 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1892 g_object_ref (priv->empty_view);
1893 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1896 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1899 priv->contents_style = style;
1901 switch (priv->contents_style) {
1902 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1903 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1904 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1907 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1909 TnyFolderStore *selected_folderstore =
1910 modest_folder_view_get_selected (priv->folder_view);
1911 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1912 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1913 TNY_ACCOUNT (selected_folderstore));
1915 wrap_in_scrolled_window (priv->contents_widget,
1916 priv->details_widget);
1918 g_object_unref (selected_folderstore);
1919 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1925 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1926 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1927 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1931 g_return_if_reached ();
1935 gtk_widget_show_all (priv->contents_widget);
1938 ModestMainWindowContentsStyle
1939 modest_main_window_get_contents_style (ModestMainWindow *self)
1941 ModestMainWindowPrivate *priv;
1943 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1945 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1946 return priv->contents_style;
1951 on_configuration_key_changed (ModestConf* conf,
1953 ModestConfEvent event,
1954 ModestConfNotificationId id,
1955 ModestMainWindow *self)
1957 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1958 TnyAccount *account;
1961 priv->notification_id != id ||
1962 strcmp (key, MODEST_CONF_DEVICE_NAME))
1965 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1968 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1969 if (TNY_IS_ACCOUNT (account) &&
1970 !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1973 const gchar *device_name;
1977 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1978 label = GTK_LABEL (children->data);
1980 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1981 MODEST_CONF_DEVICE_NAME, NULL);
1983 new_text = g_strdup_printf ("%s: %s",
1984 _("mcen_fi_localroot_description"),
1987 gtk_label_set_text (label, new_text);
1988 gtk_widget_show (GTK_WIDGET (label));
1991 g_list_free (children);
1993 g_object_unref (account);
1997 set_toolbar_transfer_mode (ModestMainWindow *self)
1999 ModestMainWindowPrivate *priv = NULL;
2001 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2003 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2005 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2007 if (priv->progress_bar_timeout > 0) {
2008 g_source_remove (priv->progress_bar_timeout);
2009 priv->progress_bar_timeout = 0;
2016 set_toolbar_mode (ModestMainWindow *self,
2017 ModestToolBarModes mode)
2019 ModestWindowPrivate *parent_priv = NULL;
2020 ModestMainWindowPrivate *priv = NULL;
2021 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2023 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2025 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2026 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2028 /* In case this was called before the toolbar exists: */
2029 if (!(parent_priv->toolbar))
2032 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2034 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2035 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2036 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2038 /* Sets current toolbar mode */
2039 priv->current_toolbar_mode = mode;
2041 /* Show and hide toolbar items */
2043 case TOOLBAR_MODE_NORMAL:
2045 gtk_action_set_visible (sort_action, TRUE);
2047 gtk_action_set_visible (refresh_action, TRUE);
2048 if (priv->progress_toolitem) {
2049 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2050 gtk_widget_hide (priv->progress_toolitem);
2052 if (priv->progress_bar)
2053 gtk_widget_hide (priv->progress_bar);
2056 gtk_action_set_visible (cancel_action, FALSE);
2058 /* Hide toolbar if optimized view is enabled */
2059 if (priv->optimized_view)
2060 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2062 case TOOLBAR_MODE_TRANSFER:
2064 gtk_action_set_visible (sort_action, FALSE);
2066 gtk_action_set_visible (refresh_action, FALSE);
2068 gtk_action_set_visible (cancel_action, TRUE);
2069 if (priv->progress_toolitem) {
2070 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2071 gtk_widget_show (priv->progress_toolitem);
2073 if (priv->progress_bar)
2074 gtk_widget_show (priv->progress_bar);
2076 /* Show toolbar if it's hiden (optimized view ) */
2077 if (priv->optimized_view)
2078 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2081 g_return_if_reached ();
2086 cancel_progressbar (GtkToolButton *toolbutton,
2087 ModestMainWindow *self)
2090 ModestMainWindowPrivate *priv;
2092 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2094 /* Get operation observers and cancel all the operations */
2095 tmp = priv->progress_widgets;
2097 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2098 tmp=g_slist_next(tmp);
2103 observers_empty (ModestMainWindow *self)
2106 ModestMainWindowPrivate *priv;
2107 gboolean is_empty = TRUE;
2108 guint pending_ops = 0;
2110 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2111 tmp = priv->progress_widgets;
2113 /* Check all observers */
2114 while (tmp && is_empty) {
2115 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2116 is_empty = pending_ops == 0;
2118 tmp = g_slist_next(tmp);
2125 on_queue_changed (ModestMailOperationQueue *queue,
2126 ModestMailOperation *mail_op,
2127 ModestMailOperationQueueNotification type,
2128 ModestMainWindow *self)
2130 ModestMainWindowPrivate *priv;
2131 ModestMailOperationTypeOperation op_type;
2132 ModestToolBarModes mode;
2134 gboolean mode_changed = FALSE;
2136 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2137 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2139 /* Get toolbar mode from operation id*/
2140 op_type = modest_mail_operation_get_type_operation (mail_op);
2142 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2143 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2144 mode = TOOLBAR_MODE_TRANSFER;
2145 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2146 mode_changed = TRUE;
2149 mode = TOOLBAR_MODE_NORMAL;
2154 /* Add operation observers and change toolbar if neccessary*/
2155 tmp = priv->progress_widgets;
2157 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2158 if (mode == TOOLBAR_MODE_TRANSFER) {
2160 set_toolbar_transfer_mode(self);
2163 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2165 tmp = g_slist_next (tmp);
2169 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2170 /* Change toolbar mode */
2171 if (mode == TOOLBAR_MODE_TRANSFER) {
2173 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2175 tmp = g_slist_next (tmp);
2178 /* If no more operations are being observed, NORMAL mode is enabled again */
2179 if (observers_empty (self)) {
2180 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2190 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2192 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2194 /* Get account data */
2195 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2196 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2198 /* Set the new visible & active account */
2199 if (acc_data && acc_data->store_account) {
2200 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2201 acc_data->store_account->account_name);
2202 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2205 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2209 modest_account_mgr_free_account_data (mgr, acc_data);
2212 /* Make sure that at least one account is "viewed": */
2214 set_at_least_one_account_visible(ModestMainWindow *self)
2216 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2217 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2219 if (!(priv->folder_view)) {
2220 /* It is too early to do this. */
2224 const gchar *active_server_account_name =
2225 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2226 if (!active_server_account_name ||
2227 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2229 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2230 if (first_modest_name) {
2231 set_account_visible (self, first_modest_name);
2232 g_free (first_modest_name);
2238 on_show_account_action_activated (GtkAction *action,
2241 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2243 const gchar *acc_name = gtk_action_get_name (action);
2244 set_account_visible (self, acc_name);
2248 refresh_account (const gchar *account_name)
2252 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2254 /* If account_name == NULL, we must update all (option All) */
2256 modest_ui_actions_do_send_receive_all (win);
2258 modest_ui_actions_do_send_receive (account_name, win);
2263 on_refresh_account_action_activated (GtkAction *action,
2266 refresh_account ((const gchar*) user_data);
2270 on_send_receive_csm_activated (GtkMenuItem *item,
2273 refresh_account ((const gchar*) user_data);
2277 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2279 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2281 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2287 on_folder_view_focus_in (GtkWidget *widget,
2288 GdkEventFocus *event,
2291 ModestMainWindow *main_window = NULL;
2293 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2294 main_window = MODEST_MAIN_WINDOW (userdata);
2296 /* Update toolbar dimming state */
2297 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2303 on_header_view_focus_in (GtkWidget *widget,
2304 GdkEventFocus *event,
2307 ModestMainWindow *main_window = NULL;
2308 ModestMainWindowPrivate *priv = NULL;
2310 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2311 main_window = MODEST_MAIN_WINDOW (userdata);
2312 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2314 if (modest_header_view_has_selected_headers (MODEST_HEADER_VIEW (priv->header_view))) {
2315 TnyList *selection = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (priv->header_view));
2316 TnyIterator *iterator = tny_list_create_iterator (selection);
2319 tny_iterator_first (iterator);
2320 header = TNY_HEADER (tny_iterator_get_current (iterator));
2322 if (tny_header_get_subject (header))
2323 gtk_window_set_title (GTK_WINDOW(main_window), tny_header_get_subject (header));
2325 gtk_window_set_title (GTK_WINDOW (main_window), _("mail_va_no_subject"));
2328 g_object_unref (header);
2330 g_object_unref (iterator);
2331 g_object_unref (selection);
2335 /* Update toolbar dimming state */
2336 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2342 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2343 TnyFolderStore *folder_store,
2345 ModestMainWindow *main_window)
2347 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2348 GtkAction *action = NULL;
2349 gboolean show_reply = TRUE;
2350 gboolean show_forward = TRUE;
2351 gboolean show_cancel_send = FALSE;
2352 gboolean show_clipboard = TRUE;
2353 gboolean show_delete = TRUE;
2356 if (TNY_IS_ACCOUNT (folder_store)) {
2357 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2358 } else if (TNY_IS_FOLDER (folder_store)) {
2359 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2360 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2361 TNY_FOLDER (folder_store));
2362 switch (folder_type) {
2363 case TNY_FOLDER_TYPE_DRAFTS:
2364 show_clipboard = show_delete = TRUE;
2365 show_reply = show_forward = show_cancel_send = FALSE;
2367 case TNY_FOLDER_TYPE_SENT:
2368 show_forward = show_clipboard = show_delete = TRUE;
2369 show_reply = show_cancel_send = FALSE;
2371 case TNY_FOLDER_TYPE_OUTBOX:
2372 show_clipboard = show_delete = show_cancel_send = TRUE;
2373 show_reply = show_forward = FALSE;
2376 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2377 show_cancel_send = FALSE;
2380 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2381 show_cancel_send = FALSE;
2386 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2387 gtk_action_set_visible (action, show_reply);
2388 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2389 gtk_action_set_visible (action, show_reply);
2390 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2391 gtk_action_set_visible (action, show_forward);
2392 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2393 gtk_action_set_visible (action, show_cancel_send);
2394 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCut");
2395 gtk_action_set_visible (action, show_clipboard);
2396 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCopy");
2397 gtk_action_set_visible (action, show_clipboard);
2398 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMPaste");
2399 gtk_action_set_visible (action, show_clipboard);
2400 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2401 gtk_action_set_visible (action, show_delete);
2403 /* We finally call to the ui actions handler, after updating properly
2404 * the header view CSM */
2405 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2410 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2411 GtkTreeModel *model,
2412 GtkTreeRowReference *row_reference,
2413 ModestMainWindow *self)
2415 ModestMainWindowPrivate *priv = NULL;
2416 GtkTreeModel *header_model = NULL;
2417 GtkTreePath *path = NULL;
2419 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2420 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2421 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2423 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2424 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2426 /* Do nothing if we changed the folder in the main view */
2427 if (header_model != model)
2430 /* Select the message in the header view */
2431 path = gtk_tree_row_reference_get_path (row_reference);
2432 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2434 gtk_tree_path_free (path);