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);
1368 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1369 /* Remove header view */
1370 g_object_ref (priv->contents_widget);
1371 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1373 /* Reparent the main paned */
1374 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1375 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1379 g_return_if_reached ();
1382 /* Let header view grab the focus if it's being shown */
1383 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1384 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1386 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1389 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1392 ModestMainWindowStyle
1393 modest_main_window_get_style (ModestMainWindow *self)
1395 ModestMainWindowPrivate *priv;
1397 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1399 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1406 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1408 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1409 ModestWindowPrivate *parent_priv;
1410 ModestWindowMgr *mgr;
1411 gboolean is_fullscreen;
1412 GtkAction *fs_toggle_action;
1415 mgr = modest_runtime_get_window_mgr ();
1417 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1419 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1421 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1422 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1423 if (is_fullscreen != active) {
1424 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1433 set_homogeneous (GtkWidget *widget,
1436 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1437 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1441 modest_main_window_show_toolbar (ModestWindow *self,
1442 gboolean show_toolbar)
1444 ModestMainWindowPrivate *priv = NULL;
1445 ModestWindowPrivate *parent_priv = NULL;
1446 GtkWidget *reply_button = NULL, *menu = NULL;
1447 GtkWidget *placeholder = NULL;
1450 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1451 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1452 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1454 /* Set optimized view status */
1455 priv->optimized_view = !show_toolbar;
1457 if (!parent_priv->toolbar) {
1458 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1461 /* Set homogeneous toolbar */
1462 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1463 set_homogeneous, NULL);
1465 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1466 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1467 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1468 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1469 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1470 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1471 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1474 /* Add ProgressBar (Transfer toolbar) */
1475 priv->progress_bar = modest_progress_bar_widget_new ();
1476 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1477 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1478 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1479 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1480 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1482 /* Connect cancel 'clicked' signal to abort progress mode */
1483 g_signal_connect(priv->cancel_toolitem, "clicked",
1484 G_CALLBACK(cancel_progressbar),
1487 /* Add it to the observers list */
1488 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1491 hildon_window_add_toolbar (HILDON_WINDOW (self),
1492 GTK_TOOLBAR (parent_priv->toolbar));
1494 /* Set reply button tap and hold menu */
1495 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1496 "/ToolBar/ToolbarMessageReply");
1497 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1498 "/ToolbarReplyCSM");
1499 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1501 /* Set send & receive button tap and hold menu */
1502 update_menus (MODEST_MAIN_WINDOW (self));
1506 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1507 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1508 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1510 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1511 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1513 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1518 on_account_inserted (TnyAccountStore *accoust_store,
1519 TnyAccount *account,
1522 update_menus (MODEST_MAIN_WINDOW (user_data));
1526 on_account_changed (ModestAccountMgr* mgr,
1527 const gchar* account,
1530 gchar *default_account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
1532 /* Actually, we only want to know when another account has become
1533 * the default account, but there is no default_account_changed
1534 * signal in ModestAccountMgr. */
1535 if(strcmp(account, default_account) == 0)
1536 update_menus (MODEST_MAIN_WINDOW (user_data));
1538 g_free (default_account);
1542 on_account_removed (TnyAccountStore *accoust_store,
1543 TnyAccount *account,
1546 update_menus (MODEST_MAIN_WINDOW (user_data));
1550 * This function manages the key events used to navigate between
1551 * header and folder views (when the window is in split view)
1554 * -------------------------------------------------
1555 * HeaderView GDK_Left Move focus to folder view
1556 * FolderView GDK_Right Move focus to header view
1558 * There is no need to scroll to selected row, the widgets will be the
1559 * responsibles of doing that (probably managing the focus-in event
1562 on_inner_widgets_key_pressed (GtkWidget *widget,
1566 ModestMainWindowPrivate *priv;
1568 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1570 /* Do nothing if we're in SIMPLE style */
1571 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1574 if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1575 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1576 else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1577 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1583 set_alignment (GtkWidget *widget,
1586 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1587 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1591 create_empty_view (void)
1593 GtkLabel *label = NULL;
1594 GtkWidget *align = NULL;
1596 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1597 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1598 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1599 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1601 return GTK_WIDGET(align);
1605 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1607 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1612 gchar *gray_color_markup;
1614 vbox = gtk_vbox_new (FALSE, 0);
1616 /* Obtain the secondary text color. We need a realized widget, that's why
1617 we get styled_widget from outside */
1618 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1620 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1621 gray_color_markup = modest_text_utils_get_color_string (&color);
1623 // gray_color_markup is freed below
1624 gray_color_markup = g_strdup ("#BBBBBB");
1626 /* Account description: */
1628 if (modest_tny_account_is_virtual_local_folders (account)
1629 || (modest_tny_account_is_memory_card_account (account))) {
1631 /* Local folders: */
1633 /* Get device name */
1634 gchar *device_name = NULL;
1635 if (modest_tny_account_is_virtual_local_folders (account))
1636 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1637 MODEST_CONF_DEVICE_NAME, NULL);
1639 device_name = g_strdup (tny_account_get_name (account));
1641 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), ""); //TODO: Why the ""?
1642 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1643 gray_color_markup, tmp, device_name);
1645 label_w = gtk_label_new (NULL);
1646 gtk_label_set_markup (GTK_LABEL (label_w), label);
1647 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1648 g_free (device_name);
1651 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1652 gtk_box_pack_start (GTK_BOX (vbox),
1653 gtk_label_new (tny_account_get_name (account)),
1656 /* Other accounts, such as IMAP and POP: */
1661 /* Put proto in uppercase */
1662 proto = g_string_new (tny_account_get_proto (account));
1663 proto = g_string_ascii_up (proto);
1665 /* note: mcen_fi_localroot_description is something like "%s account"
1666 * however, we should display "%s account: %s"... therefore, ugly tmp */
1667 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1668 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1669 gray_color_markup, tmp, tny_account_get_name (account));
1672 label_w = gtk_label_new (NULL);
1673 gtk_label_set_markup (GTK_LABEL (label_w), label);
1674 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1675 g_string_free (proto, TRUE);
1681 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1682 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1683 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1684 modest_tny_folder_store_get_message_count (folder_store));
1685 label_w = gtk_label_new (NULL);
1686 gtk_label_set_markup (GTK_LABEL (label_w), label);
1687 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1691 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1693 _("mcen_fi_rootfolder_folders"),
1694 modest_tny_folder_store_get_folder_count (folder_store));
1695 label_w = gtk_label_new (NULL);
1696 gtk_label_set_markup (GTK_LABEL (label_w), label);
1697 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1701 if (modest_tny_account_is_virtual_local_folders (account)
1702 || modest_tny_account_is_memory_card_account (account)) {
1704 gchar *size = modest_text_utils_get_display_size (
1705 modest_tny_folder_store_get_local_size (folder_store));
1707 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1708 gray_color_markup, _("mcen_fi_rootfolder_size"),
1712 label_w = gtk_label_new (NULL);
1713 gtk_label_set_markup (GTK_LABEL (label_w), label);
1714 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1716 } else if (TNY_IS_ACCOUNT(folder_store)) {
1717 TnyAccount *account = TNY_ACCOUNT(folder_store);
1719 time_t last_updated;
1720 gchar *last_updated_string;
1721 /* Get last updated from configuration */
1722 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (),
1723 tny_account_get_id (account),
1724 MODEST_ACCOUNT_LAST_UPDATED,
1726 if (last_updated > 0)
1727 last_updated_string = modest_text_utils_get_display_date(last_updated);
1729 last_updated_string = g_strdup (_("mcen_va_never"));
1731 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1732 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1733 label_w = gtk_label_new (NULL);
1734 gtk_label_set_markup (GTK_LABEL (label_w), label);
1735 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1736 g_free (last_updated_string);
1740 g_free (gray_color_markup);
1743 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1749 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1751 ModestMainWindowPrivate *priv = NULL;
1753 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1755 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1757 return priv->send_receive_in_progress;
1761 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1763 GtkAction *action = NULL;
1764 GtkWidget *widget = NULL;
1765 ModestMainWindowPrivate *priv = NULL;
1767 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1768 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1770 priv->send_receive_in_progress = TRUE;
1772 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1773 gtk_action_set_sensitive (action, FALSE);
1774 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1775 /* gtk_action_set_sensitive (action, FALSE); */
1776 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1777 gtk_widget_set_sensitive (widget, FALSE);
1781 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1783 GtkAction *action = NULL;
1784 GtkWidget *widget = NULL;
1785 ModestMainWindowPrivate *priv = NULL;
1787 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1788 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1790 priv->send_receive_in_progress = FALSE;
1792 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1793 gtk_action_set_sensitive (action, TRUE);
1794 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1795 /* gtk_action_set_sensitive (action, TRUE); */
1796 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1797 gtk_widget_set_sensitive (widget, TRUE);
1802 _on_msg_count_changed (ModestHeaderView *header_view,
1804 TnyFolderChange *change,
1805 ModestMainWindow *main_window)
1807 printf ("DEBUG: %s\n", __FUNCTION__);
1808 gboolean folder_empty = FALSE;
1809 gboolean all_marked_as_deleted = FALSE;
1810 TnyFolderChangeChanged changed;
1811 ModestMainWindowPrivate *priv;
1813 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1814 g_return_if_fail (TNY_IS_FOLDER(folder));
1815 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1816 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1818 changed = tny_folder_change_get_changed (change);
1820 /* If something changes */
1821 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1822 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1824 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1826 printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1828 /* Check header removed (hide marked as DELETED headers) */
1829 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1830 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1833 /* Check if all messages are marked to be deleted */
1834 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1835 folder_empty = folder_empty || all_marked_as_deleted ;
1837 /* Set contents style of headers view */
1839 modest_main_window_set_contents_style (main_window,
1840 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1841 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1844 modest_main_window_set_contents_style (main_window,
1845 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1851 modest_main_window_set_contents_style (ModestMainWindow *self,
1852 ModestMainWindowContentsStyle style)
1854 ModestMainWindowPrivate *priv;
1856 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1858 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1860 /* We allow to set the same content style than the previously
1861 set if there are details, because it could happen when we're
1862 selecting different accounts consecutively */
1863 if ((priv->contents_style == style) &&
1864 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1867 /* Remove previous child. Delete it if it was an account
1869 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1871 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1872 g_object_ref (content);
1873 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1874 g_object_ref (priv->empty_view);
1875 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1878 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1881 priv->contents_style = style;
1883 switch (priv->contents_style) {
1884 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1885 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1886 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1889 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1891 TnyFolderStore *selected_folderstore =
1892 modest_folder_view_get_selected (priv->folder_view);
1893 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1894 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1895 TNY_ACCOUNT (selected_folderstore));
1897 wrap_in_scrolled_window (priv->contents_widget,
1898 priv->details_widget);
1900 g_object_unref (selected_folderstore);
1901 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1907 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1908 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1909 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1913 g_return_if_reached ();
1917 gtk_widget_show_all (priv->contents_widget);
1920 ModestMainWindowContentsStyle
1921 modest_main_window_get_contents_style (ModestMainWindow *self)
1923 ModestMainWindowPrivate *priv;
1925 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1927 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1928 return priv->contents_style;
1933 on_configuration_key_changed (ModestConf* conf,
1935 ModestConfEvent event,
1936 ModestConfNotificationId id,
1937 ModestMainWindow *self)
1939 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1940 TnyAccount *account;
1943 priv->notification_id != id ||
1944 strcmp (key, MODEST_CONF_DEVICE_NAME))
1947 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1950 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1951 if (TNY_IS_ACCOUNT (account) &&
1952 !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1955 const gchar *device_name;
1959 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1960 label = GTK_LABEL (children->data);
1962 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1963 MODEST_CONF_DEVICE_NAME, NULL);
1965 new_text = g_strdup_printf ("%s: %s",
1966 _("mcen_fi_localroot_description"),
1969 gtk_label_set_text (label, new_text);
1970 gtk_widget_show (GTK_WIDGET (label));
1973 g_list_free (children);
1975 g_object_unref (account);
1979 set_toolbar_transfer_mode (ModestMainWindow *self)
1981 ModestMainWindowPrivate *priv = NULL;
1983 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1985 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1987 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1989 if (priv->progress_bar_timeout > 0) {
1990 g_source_remove (priv->progress_bar_timeout);
1991 priv->progress_bar_timeout = 0;
1998 set_toolbar_mode (ModestMainWindow *self,
1999 ModestToolBarModes mode)
2001 ModestWindowPrivate *parent_priv = NULL;
2002 ModestMainWindowPrivate *priv = NULL;
2003 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2005 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2007 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2008 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2010 /* In case this was called before the toolbar exists: */
2011 if (!(parent_priv->toolbar))
2014 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2016 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2017 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2018 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2020 /* Sets current toolbar mode */
2021 priv->current_toolbar_mode = mode;
2023 /* Checks the dimming rules */
2024 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2026 /* Show and hide toolbar items */
2028 case TOOLBAR_MODE_NORMAL:
2030 gtk_action_set_visible (sort_action, TRUE);
2032 gtk_action_set_visible (refresh_action, TRUE);
2033 if (priv->progress_toolitem) {
2034 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2035 gtk_widget_hide (priv->progress_toolitem);
2037 if (priv->progress_bar)
2038 gtk_widget_hide (priv->progress_bar);
2041 gtk_action_set_visible (cancel_action, FALSE);
2043 /* Hide toolbar if optimized view is enabled */
2044 if (priv->optimized_view)
2045 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2047 case TOOLBAR_MODE_TRANSFER:
2049 gtk_action_set_visible (sort_action, FALSE);
2051 gtk_action_set_visible (refresh_action, FALSE);
2053 gtk_action_set_visible (cancel_action, TRUE);
2054 if (priv->progress_toolitem) {
2055 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2056 gtk_widget_show (priv->progress_toolitem);
2058 if (priv->progress_bar)
2059 gtk_widget_show (priv->progress_bar);
2061 /* Show toolbar if it's hiden (optimized view ) */
2062 if (priv->optimized_view)
2063 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2066 g_return_if_reached ();
2071 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2073 ModestMainWindowPrivate *priv;
2075 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2076 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2078 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2082 cancel_progressbar (GtkToolButton *toolbutton,
2083 ModestMainWindow *self)
2086 ModestMainWindowPrivate *priv;
2088 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2090 /* Get operation observers and cancel all the operations */
2091 tmp = priv->progress_widgets;
2093 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2094 tmp=g_slist_next(tmp);
2099 observers_empty (ModestMainWindow *self)
2102 ModestMainWindowPrivate *priv;
2103 gboolean is_empty = TRUE;
2104 guint pending_ops = 0;
2106 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2107 tmp = priv->progress_widgets;
2109 /* Check all observers */
2110 while (tmp && is_empty) {
2111 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2112 is_empty = pending_ops == 0;
2114 tmp = g_slist_next(tmp);
2121 on_queue_changed (ModestMailOperationQueue *queue,
2122 ModestMailOperation *mail_op,
2123 ModestMailOperationQueueNotification type,
2124 ModestMainWindow *self)
2126 ModestMainWindowPrivate *priv;
2127 ModestMailOperationTypeOperation op_type;
2128 ModestToolBarModes mode;
2130 gboolean mode_changed = FALSE;
2132 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2133 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2135 /* Get toolbar mode from operation id*/
2136 op_type = modest_mail_operation_get_type_operation (mail_op);
2138 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2139 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2140 mode = TOOLBAR_MODE_TRANSFER;
2141 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2142 mode_changed = TRUE;
2145 mode = TOOLBAR_MODE_NORMAL;
2150 /* Add operation observers and change toolbar if neccessary*/
2151 tmp = priv->progress_widgets;
2153 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2154 if (mode == TOOLBAR_MODE_TRANSFER) {
2156 set_toolbar_transfer_mode(self);
2159 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2161 tmp = g_slist_next (tmp);
2165 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2166 /* Change toolbar mode */
2167 if (mode == TOOLBAR_MODE_TRANSFER) {
2169 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2171 tmp = g_slist_next (tmp);
2174 /* If no more operations are being observed, NORMAL mode is enabled again */
2175 if (observers_empty (self)) {
2176 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2186 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2188 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2190 /* Get account data */
2191 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2192 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2194 /* Set the new visible & active account */
2195 if (acc_data && acc_data->store_account) {
2196 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2197 acc_data->store_account->account_name);
2198 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2201 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2205 modest_account_mgr_free_account_data (mgr, acc_data);
2208 /* Make sure that at least one account is "viewed": */
2210 set_at_least_one_account_visible(ModestMainWindow *self)
2212 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2213 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2215 if (!(priv->folder_view)) {
2216 /* It is too early to do this. */
2220 const gchar *active_server_account_name =
2221 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2222 if (!active_server_account_name ||
2223 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2225 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2226 if (first_modest_name) {
2227 set_account_visible (self, first_modest_name);
2228 g_free (first_modest_name);
2234 on_show_account_action_activated (GtkAction *action,
2237 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2239 const gchar *acc_name = gtk_action_get_name (action);
2240 set_account_visible (self, acc_name);
2244 refresh_account (const gchar *account_name)
2248 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2250 /* If account_name == NULL, we must update all (option All) */
2252 modest_ui_actions_do_send_receive_all (win);
2254 modest_ui_actions_do_send_receive (account_name, win);
2259 on_refresh_account_action_activated (GtkAction *action,
2262 refresh_account ((const gchar*) user_data);
2266 on_send_receive_csm_activated (GtkMenuItem *item,
2269 refresh_account ((const gchar*) user_data);
2273 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2275 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2277 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2283 on_folder_view_focus_in (GtkWidget *widget,
2284 GdkEventFocus *event,
2287 ModestMainWindow *main_window = NULL;
2289 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2290 main_window = MODEST_MAIN_WINDOW (userdata);
2292 /* Update toolbar dimming state */
2293 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2299 on_header_view_focus_in (GtkWidget *widget,
2300 GdkEventFocus *event,
2303 ModestMainWindow *main_window = NULL;
2304 ModestMainWindowPrivate *priv = NULL;
2306 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2307 main_window = MODEST_MAIN_WINDOW (userdata);
2308 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2310 /* Update toolbar dimming state */
2311 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2317 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2318 TnyFolderStore *folder_store,
2320 ModestMainWindow *main_window)
2322 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2323 GtkAction *action = NULL;
2324 gboolean show_reply = TRUE;
2325 gboolean show_forward = TRUE;
2326 gboolean show_cancel_send = FALSE;
2327 gboolean show_clipboard = TRUE;
2328 gboolean show_delete = TRUE;
2331 if (TNY_IS_ACCOUNT (folder_store)) {
2332 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2333 } else if (TNY_IS_FOLDER (folder_store)) {
2334 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2335 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2336 TNY_FOLDER (folder_store));
2337 switch (folder_type) {
2338 case TNY_FOLDER_TYPE_DRAFTS:
2339 show_clipboard = show_delete = TRUE;
2340 show_reply = show_forward = show_cancel_send = FALSE;
2342 case TNY_FOLDER_TYPE_SENT:
2343 show_forward = show_clipboard = show_delete = TRUE;
2344 show_reply = show_cancel_send = FALSE;
2346 case TNY_FOLDER_TYPE_OUTBOX:
2347 show_clipboard = show_delete = show_cancel_send = TRUE;
2348 show_reply = show_forward = FALSE;
2351 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2352 show_cancel_send = FALSE;
2355 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2356 show_cancel_send = FALSE;
2361 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2362 gtk_action_set_visible (action, show_reply);
2363 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2364 gtk_action_set_visible (action, show_reply);
2365 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2366 gtk_action_set_visible (action, show_forward);
2367 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2368 gtk_action_set_visible (action, show_cancel_send);
2369 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCut");
2370 gtk_action_set_visible (action, show_clipboard);
2371 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCopy");
2372 gtk_action_set_visible (action, show_clipboard);
2373 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMPaste");
2374 gtk_action_set_visible (action, show_clipboard);
2375 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2376 gtk_action_set_visible (action, show_delete);
2378 /* We finally call to the ui actions handler, after updating properly
2379 * the header view CSM */
2380 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2385 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2386 GtkTreeModel *model,
2387 GtkTreeRowReference *row_reference,
2388 ModestMainWindow *self)
2390 ModestMainWindowPrivate *priv = NULL;
2391 GtkTreeModel *header_model = NULL;
2392 GtkTreePath *path = NULL;
2394 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2395 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2396 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2398 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2399 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2401 /* Do nothing if we changed the folder in the main view */
2402 if (header_model != model)
2405 /* Select the message in the header view */
2406 path = gtk_tree_row_reference_get_path (row_reference);
2407 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2409 gtk_tree_path_free (path);