1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-maemo-utils.h>
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-mail-operation.h"
60 #include "modest-icon-names.h"
61 #include "modest-progress-bar-widget.h"
62 #include "modest-text-utils.h"
63 #include "modest-ui-dimming-manager.h"
64 #include "maemo/modest-osso-state-saving.h"
65 #include "modest-text-utils.h"
66 #include "modest-signal-mgr.h"
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-program.h>
71 #include <hildon/hildon-program.h>
72 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
74 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
81 /* 'private'/'protected' functions */
82 static void modest_main_window_class_init (ModestMainWindowClass *klass);
83 static void modest_main_window_init (ModestMainWindow *obj);
84 static void modest_main_window_finalize (GObject *obj);
86 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
87 GdkEventWindowState *event,
90 static void connect_signals (ModestMainWindow *self);
92 static void modest_main_window_disconnect_signals (ModestWindow *self);
94 static void restore_settings (ModestMainWindow *self,
95 gboolean do_folder_view_too);
97 static void save_state (ModestWindow *self);
99 static void update_menus (ModestMainWindow* self);
101 static void modest_main_window_show_toolbar (ModestWindow *window,
102 gboolean show_toolbar);
104 static void cancel_progressbar (GtkToolButton *toolbutton,
105 ModestMainWindow *self);
107 static void on_queue_changed (ModestMailOperationQueue *queue,
108 ModestMailOperation *mail_op,
109 ModestMailOperationQueueNotification type,
110 ModestMainWindow *self);
112 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
115 on_account_inserted (TnyAccountStore *accoust_store,
120 on_account_removed (TnyAccountStore *accoust_store,
124 static void on_default_account_changed (ModestAccountMgr* mgr,
127 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
131 static void on_configuration_key_changed (ModestConf* conf,
133 ModestConfEvent event,
134 ModestConfNotificationId id,
135 ModestMainWindow *self);
137 static void set_toolbar_mode (ModestMainWindow *self,
138 ModestToolBarModes mode);
140 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
142 static void on_show_account_action_toggled (GtkToggleAction *action,
145 static void on_refresh_account_action_activated (GtkAction *action,
148 static void on_account_updated (ModestAccountMgr* mgr, gchar* account_name,
151 static void on_send_receive_csm_activated (GtkMenuItem *item,
154 static void on_msg_count_changed (ModestHeaderView *header_view,
156 TnyFolderChange *change,
157 ModestMainWindow *main_window);
159 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
162 static GtkWidget * create_empty_view (void);
164 static gboolean on_folder_view_focus_in (GtkWidget *widget,
165 GdkEventFocus *event,
168 static gboolean on_header_view_focus_in (GtkWidget *widget,
169 GdkEventFocus *event,
172 static void on_folder_selection_changed (ModestFolderView *folder_view,
173 TnyFolderStore *folder_store,
175 ModestMainWindow *main_window);
177 static void set_at_least_one_account_visible(ModestMainWindow *self);
179 static void on_updating_msg_list (ModestHeaderView *header_view,
183 static gboolean restore_paned_timeout_handler (gpointer *data);
185 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
186 struct _ModestMainWindowPrivate {
187 GtkWidget *msg_paned;
188 GtkWidget *main_paned;
189 GtkWidget *main_vbox;
190 GtkWidget *contents_widget;
191 GtkWidget *empty_view;
193 /* Progress observers */
194 GtkWidget *progress_bar;
195 GSList *progress_widgets;
198 GtkWidget *progress_toolitem;
199 GtkWidget *cancel_toolitem;
200 GtkWidget *sort_toolitem;
201 GtkWidget *refresh_toolitem;
202 ModestToolBarModes current_toolbar_mode;
204 /* Merge ids used to add/remove accounts to the ViewMenu*/
205 GByteArray *merge_ids;
206 GtkActionGroup *view_additions_group;
208 /* On-demand widgets */
209 GtkWidget *accounts_popup;
210 GtkWidget *details_widget;
212 /* Optimized view enabled */
213 gboolean optimized_view;
215 /* Optimized view enabled */
216 gboolean send_receive_in_progress;
218 ModestHeaderView *header_view;
219 ModestFolderView *folder_view;
221 ModestMainWindowStyle style;
222 ModestMainWindowContentsStyle contents_style;
224 guint progress_bar_timeout;
225 guint restore_paned_timeout;
227 /* Signal handler UIDs */
228 GList *queue_err_signals;
231 /* "Updating" banner for header view */
232 GtkWidget *updating_banner;
233 guint updating_banner_timeout;
235 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
236 MODEST_TYPE_MAIN_WINDOW, \
237 ModestMainWindowPrivate))
239 typedef struct _GetMsgAsyncHelper {
240 ModestMainWindowPrivate *main_window_private;
242 ModestTnyMsgReplyType reply_type;
243 ModestTnyMsgForwardType forward_type;
250 static GtkWindowClass *parent_class = NULL;
253 /* Private actions */
254 /* This is the context sensitive menu: */
255 static const GtkActionEntry modest_folder_view_action_entries [] = {
257 /* Folder View CSM actions */
258 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
259 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
260 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
261 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
262 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
263 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
266 static const GtkActionEntry modest_header_view_action_entries [] = {
268 /* Header View CSM actions */
269 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
270 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
271 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
272 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
273 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
274 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
275 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
276 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
277 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
278 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
281 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
282 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
285 /************************************************************************/
288 modest_main_window_get_type (void)
290 static GType my_type = 0;
292 static const GTypeInfo my_info = {
293 sizeof(ModestMainWindowClass),
294 NULL, /* base init */
295 NULL, /* base finalize */
296 (GClassInitFunc) modest_main_window_class_init,
297 NULL, /* class finalize */
298 NULL, /* class data */
299 sizeof(ModestMainWindow),
301 (GInstanceInitFunc) modest_main_window_init,
304 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
312 modest_main_window_class_init (ModestMainWindowClass *klass)
314 GObjectClass *gobject_class;
315 gobject_class = (GObjectClass*) klass;
316 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
318 parent_class = g_type_class_peek_parent (klass);
319 gobject_class->finalize = modest_main_window_finalize;
321 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
323 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
324 modest_window_class->save_state_func = save_state;
325 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
326 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
327 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
331 modest_main_window_init (ModestMainWindow *obj)
333 ModestMainWindowPrivate *priv;
335 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
337 priv->queue_err_signals = NULL;
338 priv->msg_paned = NULL;
339 priv->main_paned = NULL;
340 priv->main_vbox = NULL;
341 priv->header_view = NULL;
342 priv->folder_view = NULL;
343 priv->contents_widget = NULL;
344 priv->accounts_popup = NULL;
345 priv->details_widget = NULL;
346 priv->empty_view = NULL;
347 priv->progress_widgets = NULL;
348 priv->progress_bar = NULL;
349 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
350 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
351 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
352 priv->merge_ids = NULL;
353 priv->optimized_view = FALSE;
354 priv->send_receive_in_progress = FALSE;
355 priv->progress_bar_timeout = 0;
356 priv->restore_paned_timeout = 0;
357 priv->sighandlers = NULL;
358 priv->updating_banner = NULL;
359 priv->updating_banner_timeout = 0;
361 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
363 "applications_email_mainview");
367 modest_main_window_finalize (GObject *obj)
369 ModestMainWindowPrivate *priv;
371 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
373 /* Sanity check: shouldn't be needed, the window mgr should
374 call this function before */
375 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
377 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
379 g_slist_free (priv->progress_widgets);
381 g_byte_array_free (priv->merge_ids, TRUE);
383 if (priv->progress_bar_timeout > 0) {
384 g_source_remove (priv->progress_bar_timeout);
385 priv->progress_bar_timeout = 0;
388 if (priv->updating_banner_timeout > 0) {
389 g_source_remove (priv->updating_banner_timeout);
390 priv->updating_banner_timeout = 0;
393 if (priv->updating_banner) {
394 gtk_widget_destroy (priv->updating_banner);
395 priv->updating_banner = NULL;
398 if (priv->restore_paned_timeout > 0) {
399 g_source_remove (priv->restore_paned_timeout);
400 priv->restore_paned_timeout = 0;
403 G_OBJECT_CLASS(parent_class)->finalize (obj);
407 modest_main_window_get_child_widget (ModestMainWindow *self,
408 ModestMainWindowWidgetType widget_type)
410 ModestMainWindowPrivate *priv;
413 g_return_val_if_fail (self, NULL);
414 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
417 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
419 switch (widget_type) {
420 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
421 widget = (GtkWidget*)priv->header_view; break;
422 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
423 widget = (GtkWidget*)priv->folder_view; break;
428 return widget ? GTK_WIDGET(widget) : NULL;
432 restore_paned_timeout_handler (gpointer *data)
434 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
435 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
438 /* Timeouts are outside the main lock */
439 gdk_threads_enter ();
440 if (GTK_WIDGET_VISIBLE (main_window)) {
441 conf = modest_runtime_get_conf ();
442 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
443 MODEST_CONF_MAIN_PANED_KEY);
445 gdk_threads_leave ();
452 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
455 ModestMainWindowPrivate *priv;
457 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
459 conf = modest_runtime_get_conf ();
461 modest_widget_memory_restore (conf, G_OBJECT(self),
462 MODEST_CONF_MAIN_WINDOW_KEY);
464 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
465 MODEST_CONF_HEADER_VIEW_KEY);
467 if (do_folder_view_too)
468 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
469 MODEST_CONF_FOLDER_VIEW_KEY);
471 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
472 MODEST_CONF_MAIN_PANED_KEY);
474 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
476 /* We need to force a redraw here in order to get the right
477 position of the horizontal paned separator */
478 gtk_widget_show (GTK_WIDGET (self));
483 save_state (ModestWindow *window)
486 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
487 ModestMainWindowPrivate *priv;
489 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
490 conf = modest_runtime_get_conf ();
492 modest_widget_memory_save (conf,G_OBJECT(self),
493 MODEST_CONF_MAIN_WINDOW_KEY);
494 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
495 MODEST_CONF_MAIN_PANED_KEY);
496 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
497 // MODEST_CONF_HEADER_VIEW_KEY);
498 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
499 MODEST_CONF_FOLDER_VIEW_KEY);
503 compare_display_names (ModestAccountData *a,
504 ModestAccountData *b)
506 return strcmp (a->display_name, b->display_name);
510 update_menus (ModestMainWindow* self)
512 GSList *account_names, *iter, *accounts;
513 ModestMainWindowPrivate *priv;
514 ModestWindowPrivate *parent_priv;
515 ModestAccountMgr *mgr;
516 gint i, num_accounts;
518 gchar *default_account;
519 const gchar *active_account_name;
520 GtkWidget *send_receive_button, *item;
521 GtkAction *send_receive_all = NULL;
524 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
525 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
527 /* Get enabled account IDs */
528 mgr = modest_runtime_get_account_mgr ();
529 account_names = modest_account_mgr_account_names (mgr, TRUE);
530 iter = account_names;
534 ModestAccountData *account_data =
535 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
536 accounts = g_slist_prepend (accounts, account_data);
540 modest_account_mgr_free_account_names (account_names);
541 account_names = NULL;
543 /* Order the list of accounts by its display name */
544 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
545 num_accounts = g_slist_length (accounts);
547 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
548 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
549 gtk_action_set_visible (send_receive_all, num_accounts > 0);
551 /* Delete old send&receive popup items. We can not just do a
552 menu_detach because it does not work well with
554 if (priv->accounts_popup)
555 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
556 (GtkCallback) gtk_widget_destroy, NULL);
558 /* Delete old entries in the View menu. Do not free groups, it
560 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
562 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
563 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
564 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
565 GTK_ACTION_GROUP (groups->data));
568 if (priv->merge_ids) {
569 for (i = 0; i < priv->merge_ids->len; i++)
570 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
571 g_byte_array_free (priv->merge_ids, TRUE);
573 /* We need to call this in order to ensure
574 that the new actions are added in the right
575 order (alphabetical) */
576 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
578 groups = g_list_next (groups);
580 priv->merge_ids = g_byte_array_sized_new (num_accounts);
582 /* Get send receive button */
583 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
584 "/ToolBar/ToolbarSendReceive");
586 /* Create the menu */
587 if (num_accounts > 1) {
588 if (!priv->accounts_popup)
589 priv->accounts_popup = gtk_menu_new ();
590 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
591 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
592 g_signal_connect (G_OBJECT (item),
594 G_CALLBACK (on_send_receive_csm_activated),
596 item = gtk_separator_menu_item_new ();
597 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
600 /* Create a new action group */
601 default_account = modest_account_mgr_get_default_account (mgr);
602 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
604 if (!active_account_name)
605 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
607 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
609 for (i = 0; i < num_accounts; i++) {
610 gchar *display_name = NULL;
611 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
614 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
618 if (default_account && account_data->account_name &&
619 !(strcmp (default_account, account_data->account_name) == 0)) {
620 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
621 account_data->display_name);
623 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
624 account_data->display_name);
627 /* Create action and add it to the action group. The
628 action name must be the account name, this way we
629 could know in the handlers the account to show */
630 if (account_data && account_data->account_name) {
631 gchar* item_name, *refresh_action_name;
633 GtkAction *view_account_action, *refresh_account_action;
635 view_account_action = GTK_ACTION (gtk_radio_action_new (account_data->account_name,
636 display_name, NULL, NULL, 0));
637 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
638 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
639 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
641 if (active_account_name) {
642 if (active_account_name && account_data->account_name &&
643 (strcmp (active_account_name, account_data->account_name) == 0)) {
644 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
648 /* Add ui from account data. We allow 2^9-1 account
649 changes in a single execution because we're
650 downcasting the guint to a guint8 in order to use a
651 GByteArray. It should be enough. */
652 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
653 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
654 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
655 gtk_ui_manager_add_ui (parent_priv->ui_manager,
657 "/MenuBar/ViewMenu/ViewMenuAdditions",
659 account_data->account_name,
660 GTK_UI_MANAGER_MENUITEM,
663 /* Connect the action signal "activate" */
664 g_signal_connect_after (G_OBJECT (view_account_action),
666 G_CALLBACK (on_show_account_action_toggled),
669 /* Create the items for the Tools->Send&Receive submenu */
670 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
671 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
672 display_name, NULL, NULL);
673 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
675 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
676 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
677 gtk_ui_manager_add_ui (parent_priv->ui_manager,
679 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
682 GTK_UI_MANAGER_MENUITEM,
684 g_free (refresh_action_name);
686 g_signal_connect_data (G_OBJECT (refresh_account_action),
688 G_CALLBACK (on_refresh_account_action_activated),
689 g_strdup (account_data->account_name),
690 (GClosureNotify) g_free,
693 /* Create item and add it to the send&receive
694 CSM. If there is only one account then
696 if (priv->accounts_popup) {
697 GtkWidget *label = gtk_label_new(NULL);
698 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
699 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
701 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
702 gtk_label_set_markup (GTK_LABEL (label), escaped);
707 gtk_label_set_text (GTK_LABEL (label), display_name);
710 item = gtk_menu_item_new ();
711 gtk_container_add (GTK_CONTAINER (item), label);
713 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
714 g_signal_connect_data (G_OBJECT (item),
716 G_CALLBACK (on_send_receive_csm_activated),
717 g_strdup (account_data->account_name),
718 (GClosureNotify) g_free,
725 g_free (display_name);
728 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
730 /* We cannot do this in the loop above because this relies on the action
731 * group being inserted. This makes the default account appear in bold.
732 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
733 for (i = 0; i < num_accounts; i++) {
734 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
736 if(account_data->account_name && default_account &&
737 strcmp (account_data->account_name, default_account) == 0) {
738 gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
740 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
741 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
745 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
746 if (GTK_IS_LABEL (child)) {
747 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
748 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
749 gtk_label_set_markup (GTK_LABEL (child), bold_name);
754 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
755 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
759 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
760 if (GTK_IS_LABEL (child)) {
761 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
762 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
763 gtk_label_set_markup (GTK_LABEL (child), bold_name);
771 modest_account_mgr_free_account_data (mgr, account_data);
774 if (priv->accounts_popup) {
775 /* Mandatory in order to view the menu contents */
776 gtk_widget_show_all (priv->accounts_popup);
778 /* Setup tap_and_hold just if was not done before*/
779 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
780 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
784 g_slist_free (accounts);
785 g_free (default_account);
788 /* Make sure that at least one account is viewed if there are any
789 * accounts, for instance when adding the first account: */
790 set_at_least_one_account_visible (self);
794 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
796 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
797 gtk_scrolled_window_add_with_viewport
798 (GTK_SCROLLED_WINDOW(win), widget);
800 gtk_container_add (GTK_CONTAINER(win),
811 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
813 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
815 GList *oerrsignals = priv->queue_err_signals;
816 while (oerrsignals) {
817 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
818 g_signal_handler_disconnect (esignal->queue, esignal->signal);
819 g_slice_free (QueueErrorSignal, esignal);
820 oerrsignals = g_list_next (oerrsignals);
822 g_list_free (priv->queue_err_signals);
823 priv->queue_err_signals = NULL;
828 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
830 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
833 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
837 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
839 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
841 /* Update visibility */
844 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
848 modest_main_window_disconnect_signals (ModestWindow *self)
850 ModestMainWindowPrivate *priv;
851 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
853 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
854 priv->sighandlers = NULL;
858 connect_signals (ModestMainWindow *self)
860 ModestWindowPrivate *parent_priv;
861 ModestMainWindowPrivate *priv;
864 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
865 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
870 modest_signal_mgr_connect (priv->sighandlers,
871 G_OBJECT(priv->folder_view), "key-press-event",
872 G_CALLBACK(on_inner_widgets_key_pressed), self);
874 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view),
875 "folder_selection_changed",
876 G_CALLBACK (on_folder_selection_changed),
879 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view),
880 "folder-display-name-changed",
881 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed),
884 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view),
886 G_CALLBACK (on_folder_view_focus_in),
889 /* Folder view CSM */
890 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
891 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
892 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
893 G_CALLBACK(_folder_view_csm_menu_activated),
897 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
898 G_CALLBACK(modest_ui_actions_on_header_selected), self);
900 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
901 G_CALLBACK(modest_ui_actions_on_header_activated), self);
903 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
904 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
906 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
907 G_CALLBACK(on_inner_widgets_key_pressed), self);
909 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
910 G_CALLBACK(on_msg_count_changed), self);
912 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
913 G_CALLBACK (on_header_view_focus_in), self);
915 modest_signal_mgr_connect (priv->sighandlers,
916 G_OBJECT (priv->header_view),
918 G_CALLBACK (on_updating_msg_list),
921 /* Header view CSM */
922 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
923 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
925 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
926 G_CALLBACK(_header_view_csm_menu_activated),
931 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
932 G_CALLBACK (modest_main_window_window_state_event),
935 /* Mail Operation Queue */
937 modest_signal_mgr_connect (priv->sighandlers,
938 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
940 G_CALLBACK (on_queue_changed), self);
942 /* Track changes in the device name */
944 modest_signal_mgr_connect (priv->sighandlers,
945 G_OBJECT(modest_runtime_get_conf ()),
947 G_CALLBACK (on_configuration_key_changed),
950 /* Track account changes. We need to refresh the toolbar */
952 modest_signal_mgr_connect (priv->sighandlers,
953 G_OBJECT (modest_runtime_get_account_store ()),
955 G_CALLBACK (on_account_inserted),
958 modest_signal_mgr_connect (priv->sighandlers,
959 G_OBJECT (modest_runtime_get_account_store ()),
961 G_CALLBACK (on_account_removed),
964 /* We need to refresh the send & receive menu to change the bold
965 * account when the default account changes. */
967 modest_signal_mgr_connect (priv->sighandlers,
968 G_OBJECT (modest_runtime_get_account_mgr ()),
969 "default_account_changed",
970 G_CALLBACK (on_default_account_changed),
974 modest_signal_mgr_connect (priv->sighandlers,
975 G_OBJECT (modest_runtime_get_account_mgr ()),
977 G_CALLBACK (on_account_updated),
981 modest_signal_mgr_connect (priv->sighandlers,
982 G_OBJECT (modest_runtime_get_account_store()),
983 "password_requested",
984 G_CALLBACK (modest_ui_actions_on_password_requested),
989 /** Idle handler, to send/receive at startup .*/
991 sync_accounts_cb (ModestMainWindow *win)
993 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
994 return FALSE; /* Do not call this idle handler again. */
999 on_hildon_program_is_topmost_notify(GObject *self,
1000 GParamSpec *propert_param, gpointer user_data)
1002 HildonProgram *app = HILDON_PROGRAM (self);
1005 ModestWindow* self = MODEST_WINDOW(user_data);
1008 /* Note that use of hildon_program_set_can_hibernate()
1009 * is generally referred to as "setting the killable flag",
1010 * though hibernation does not seem equal to death.
1013 if (hildon_program_get_is_topmost (app)) {
1014 /* Prevent hibernation when the progam comes to the foreground,
1015 * because hibernation should only happen when the application
1016 * is in the background: */
1017 hildon_program_set_can_hibernate (app, FALSE);
1019 /* Allow hibernation if the program has gone to the background: */
1021 /* However, prevent hibernation while the settings are being changed: */
1022 const gboolean hibernation_prevented =
1023 modest_window_mgr_get_hibernation_is_prevented (
1024 modest_runtime_get_window_mgr ());
1026 if (hibernation_prevented)
1027 hildon_program_set_can_hibernate (app, FALSE);
1029 /* Allow hibernation, after saving the state: */
1030 modest_osso_save_state();
1031 hildon_program_set_can_hibernate (app, TRUE);
1038 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1040 GtkWidget *folder_win = (GtkWidget *) user_data;
1041 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1043 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1044 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1046 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1048 /* Connect signals */
1049 connect_signals (MODEST_MAIN_WINDOW (self));
1051 /* Set account store */
1052 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1053 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1055 /* Load previous osso state, for instance if we are being restored from
1057 modest_osso_load_state ();
1059 /* Restore window & widget settings */
1060 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1062 /* Check if accounts exist and show the account wizard if not */
1063 gboolean accounts_exist =
1064 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1066 if (!accounts_exist) {
1067 /* This is necessary to have the main window shown behind the dialog
1068 It's an ugly hack... jschmid */
1069 gtk_widget_show_all(GTK_WIDGET(self));
1070 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1073 GtkAction *send_receive_all;
1074 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1075 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1076 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1077 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1078 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 0);
1079 modest_account_mgr_free_account_names (accounts);
1080 update_menus (MODEST_MAIN_WINDOW (self));
1085 modest_main_window_new (void)
1087 ModestMainWindow *self = NULL;
1088 ModestMainWindowPrivate *priv = NULL;
1089 ModestWindowPrivate *parent_priv = NULL;
1090 GtkWidget *folder_win = NULL;
1091 ModestDimmingRulesGroup *menu_rules_group = NULL;
1092 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1093 GtkActionGroup *action_group = NULL;
1094 GError *error = NULL;
1095 ModestConf *conf = NULL;
1096 GtkAction *action = NULL;
1097 GdkPixbuf *window_icon;
1099 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1100 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1101 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1103 parent_priv->ui_manager = gtk_ui_manager_new();
1104 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1106 action_group = gtk_action_group_new ("ModestMainWindowActions");
1107 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1109 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1110 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1112 /* Add common actions */
1113 gtk_action_group_add_actions (action_group,
1114 modest_action_entries,
1115 G_N_ELEMENTS (modest_action_entries),
1118 gtk_action_group_add_actions (action_group,
1119 modest_folder_view_action_entries,
1120 G_N_ELEMENTS (modest_folder_view_action_entries),
1123 gtk_action_group_add_actions (action_group,
1124 modest_header_view_action_entries,
1125 G_N_ELEMENTS (modest_header_view_action_entries),
1128 gtk_action_group_add_toggle_actions (action_group,
1129 modest_toggle_action_entries,
1130 G_N_ELEMENTS (modest_toggle_action_entries),
1133 gtk_action_group_add_toggle_actions (action_group,
1134 modest_main_window_toggle_action_entries,
1135 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1138 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1139 g_object_unref (action_group);
1141 /* Load the UI definition */
1142 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1143 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1144 if (error != NULL) {
1145 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1146 g_error_free (error);
1150 /* Add common dimming rules */
1151 modest_dimming_rules_group_add_rules (menu_rules_group,
1152 modest_main_window_menu_dimming_entries,
1153 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1154 MODEST_WINDOW (self));
1155 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1156 modest_main_window_toolbar_dimming_entries,
1157 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1158 MODEST_WINDOW (self));
1160 /* Insert dimming rules group for this window */
1161 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1162 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1163 g_object_unref (menu_rules_group);
1164 g_object_unref (toolbar_rules_group);
1166 /* Add accelerators */
1167 gtk_window_add_accel_group (GTK_WINDOW (self),
1168 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1170 /* Menubar. Update the state of some toggles */
1171 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1172 conf = modest_runtime_get_conf ();
1173 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1174 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1175 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1176 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1177 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1178 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1179 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1180 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1181 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1182 gtk_widget_show (parent_priv->menubar);
1184 /* Get device name */
1185 modest_maemo_utils_get_device_name ();
1189 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1190 if (!priv->header_view)
1191 g_printerr ("modest: cannot instantiate header view\n");
1192 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1193 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1194 MODEST_CONF_HEADER_VIEW_KEY);
1196 /* Other style properties of header view */
1197 g_object_set (G_OBJECT (priv->header_view),
1198 "rules-hint", FALSE,
1200 /* gtk_widget_show (priv->header_view); */
1203 priv->empty_view = create_empty_view ();
1204 gtk_widget_show (priv->empty_view);
1206 /* Create scrolled windows */
1207 folder_win = gtk_scrolled_window_new (NULL, NULL);
1208 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1209 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1211 GTK_POLICY_AUTOMATIC);
1212 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1214 GTK_POLICY_AUTOMATIC);
1215 /* gtk_widget_show (priv->contents_widget); */
1218 priv->main_paned = gtk_hpaned_new ();
1219 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1220 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1221 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1223 /* putting it all together... */
1224 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1225 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1226 gtk_widget_show (priv->main_vbox);
1228 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1230 HildonProgram *app = hildon_program_get_instance ();
1231 hildon_program_add_window (app, HILDON_WINDOW (self));
1233 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1234 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1236 g_signal_connect (G_OBJECT(self), "show",
1237 G_CALLBACK (modest_main_window_on_show), folder_win);
1239 /* Set window icon */
1240 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1242 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1243 g_object_unref (window_icon);
1246 /* Dont't restore settings here,
1247 * because it requires a gtk_widget_show(),
1248 * and we don't want to do that until later,
1249 * so that the UI is not visible for non-menu D-Bus activation.
1251 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1253 return MODEST_WINDOW(self);
1257 modest_main_window_set_style (ModestMainWindow *self,
1258 ModestMainWindowStyle style)
1260 ModestMainWindowPrivate *priv;
1261 ModestWindowPrivate *parent_priv;
1265 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1267 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1268 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1270 /* no change -> nothing to do */
1271 if (priv->style == style)
1274 /* Get toggle button and update the state if needed. This will
1275 happen only when the set_style is not invoked from the UI,
1276 for example when it's called from widget memory */
1277 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1278 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1279 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1280 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1281 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1282 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1283 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1286 priv->style = style;
1288 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1289 /* Remove main paned */
1290 g_object_ref (priv->main_paned);
1291 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1293 /* Reparent the contents widget to the main vbox */
1294 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1297 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1298 /* Remove header view */
1299 g_object_ref (priv->contents_widget);
1300 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1302 /* Reparent the main paned */
1303 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1304 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1308 g_return_if_reached ();
1311 /* Let header view grab the focus if it's being shown */
1312 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1313 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1315 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1318 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1321 ModestMainWindowStyle
1322 modest_main_window_get_style (ModestMainWindow *self)
1324 ModestMainWindowPrivate *priv;
1326 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1328 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1335 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1337 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1338 ModestWindowPrivate *parent_priv;
1339 ModestWindowMgr *mgr;
1340 gboolean is_fullscreen;
1341 GtkAction *fs_toggle_action;
1344 mgr = modest_runtime_get_window_mgr ();
1346 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1348 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1350 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1351 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1352 if (is_fullscreen != active) {
1353 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1362 set_homogeneous (GtkWidget *widget,
1365 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1366 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1370 modest_main_window_show_toolbar (ModestWindow *self,
1371 gboolean show_toolbar)
1373 ModestMainWindowPrivate *priv = NULL;
1374 ModestWindowPrivate *parent_priv = NULL;
1375 GtkWidget *reply_button = NULL, *menu = NULL;
1376 GtkWidget *placeholder = NULL;
1378 const gchar *action_name;
1381 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1382 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1383 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1385 /* Set optimized view status */
1386 priv->optimized_view = !show_toolbar;
1388 if (!parent_priv->toolbar) {
1389 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1391 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1393 /* Set homogeneous toolbar */
1394 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1395 set_homogeneous, NULL);
1397 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1398 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1399 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1400 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1401 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1402 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1403 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1404 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1406 /* Add ProgressBar (Transfer toolbar) */
1407 priv->progress_bar = modest_progress_bar_widget_new ();
1408 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1409 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1410 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1411 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1412 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1414 /* Connect cancel 'clicked' signal to abort progress mode */
1415 g_signal_connect(priv->cancel_toolitem, "clicked",
1416 G_CALLBACK(cancel_progressbar),
1419 /* Add it to the observers list */
1420 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1423 hildon_window_add_toolbar (HILDON_WINDOW (self),
1424 GTK_TOOLBAR (parent_priv->toolbar));
1426 /* Set reply button tap and hold menu */
1427 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1428 "/ToolBar/ToolbarMessageReply");
1429 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1430 "/ToolbarReplyCSM");
1431 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1433 /* Set send & receive button tap and hold menu */
1434 update_menus (MODEST_MAIN_WINDOW (self));
1438 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1439 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1440 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1442 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1443 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1444 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1446 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1448 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1452 /* Update also the actions (to update the toggles in the
1453 menus), we have to do it manually because some other window
1454 of the same time could have changed it (remember that the
1455 toolbar fullscreen mode is shared by all the windows of the
1457 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1458 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1460 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1462 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1463 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1468 on_account_inserted (TnyAccountStore *accoust_store,
1469 TnyAccount *account,
1472 update_menus (MODEST_MAIN_WINDOW (user_data));
1476 on_default_account_changed (ModestAccountMgr* mgr,
1479 update_menus (MODEST_MAIN_WINDOW (user_data));
1483 on_account_removed (TnyAccountStore *accoust_store,
1484 TnyAccount *account,
1487 update_menus (MODEST_MAIN_WINDOW (user_data));
1491 on_account_updated (ModestAccountMgr* mgr,
1492 gchar* account_name,
1495 ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1497 if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS) {
1498 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1503 * This function manages the key events used to navigate between
1504 * header and folder views (when the window is in split view)
1507 * -------------------------------------------------
1508 * HeaderView GDK_Left Move focus to folder view
1509 * FolderView GDK_Right Move focus to header view
1511 * There is no need to scroll to selected row, the widgets will be the
1512 * responsibles of doing that (probably managing the focus-in event
1515 on_inner_widgets_key_pressed (GtkWidget *widget,
1519 ModestMainWindowPrivate *priv;
1521 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1523 /* Do nothing if we're in SIMPLE style */
1524 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1527 if (MODEST_IS_HEADER_VIEW (widget)) {
1528 if (event->keyval == GDK_Left)
1529 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1530 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1531 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1532 if (selected_headers > 1) {
1533 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1537 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1538 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1544 set_alignment (GtkWidget *widget,
1547 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1548 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1552 create_empty_view (void)
1554 GtkLabel *label = NULL;
1555 GtkWidget *align = NULL;
1557 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1558 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1559 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1560 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1562 return GTK_WIDGET(align);
1566 * Free the returned string
1569 get_gray_color_markup (GtkWidget *styled_widget)
1571 gchar *gray_color_markup = NULL;
1572 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1573 /* Obtain the secondary text color. We need a realized widget, that's why
1574 we get styled_widget from outside */
1576 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1577 gray_color_markup = modest_text_utils_get_color_string (&color);
1578 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1580 if (!gray_color_markup)
1581 gray_color_markup = g_strdup ("#BBBBBB");
1583 return gray_color_markup;
1587 * Free the returned string
1590 create_device_name_visual_string (const gchar *device_name,
1591 const gchar *gray_color_markup)
1595 /* We have to use "" to fill the %s of the translation. We can
1596 not just use the device name because the device name is
1597 shown in a different color, so it could not be included
1598 into the <span> tag */
1599 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1600 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1610 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1612 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1617 gchar *gray_color_markup;
1619 vbox = gtk_vbox_new (FALSE, 0);
1621 gray_color_markup = get_gray_color_markup (styled_widget);
1623 /* Account description: */
1624 if (modest_tny_account_is_virtual_local_folders (account)
1625 || (modest_tny_account_is_memory_card_account (account))) {
1627 /* Get device name */
1628 gchar *device_name = NULL;
1629 if (modest_tny_account_is_virtual_local_folders (account))
1630 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1631 MODEST_CONF_DEVICE_NAME, NULL);
1633 device_name = g_strdup (tny_account_get_name (account));
1635 label = create_device_name_visual_string ((const gchar *) device_name,
1636 (const gchar *) gray_color_markup);
1637 label_w = gtk_label_new (NULL);
1638 gtk_label_set_markup (GTK_LABEL (label_w), label);
1639 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1640 g_free (device_name);
1643 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1644 gtk_box_pack_start (GTK_BOX (vbox),
1645 gtk_label_new (tny_account_get_name (account)),
1648 /* Other accounts, such as IMAP and POP: */
1653 /* Put proto in uppercase */
1654 proto = g_string_new (tny_account_get_proto (account));
1655 proto = g_string_ascii_up (proto);
1657 /* note: mcen_fi_localroot_description is something like "%s account"
1658 * however, we should display "%s account: %s"... therefore, ugly tmp */
1659 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1660 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1661 gray_color_markup, tmp, tny_account_get_name (account));
1664 label_w = gtk_label_new (NULL);
1665 gtk_label_set_markup (GTK_LABEL (label_w), label);
1666 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1667 g_string_free (proto, TRUE);
1673 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1674 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1675 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1676 modest_tny_folder_store_get_message_count (folder_store));
1677 label_w = gtk_label_new (NULL);
1678 gtk_label_set_markup (GTK_LABEL (label_w), label);
1679 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1683 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1685 _("mcen_fi_rootfolder_folders"),
1686 modest_tny_folder_store_get_folder_count (folder_store));
1687 label_w = gtk_label_new (NULL);
1688 gtk_label_set_markup (GTK_LABEL (label_w), label);
1689 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1693 if (modest_tny_account_is_virtual_local_folders (account)
1694 || modest_tny_account_is_memory_card_account (account)) {
1696 gchar *size = modest_text_utils_get_display_size (
1697 modest_tny_folder_store_get_local_size (folder_store));
1699 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1700 gray_color_markup, _("mcen_fi_rootfolder_size"),
1704 label_w = gtk_label_new (NULL);
1705 gtk_label_set_markup (GTK_LABEL (label_w), label);
1706 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1708 } else if (TNY_IS_ACCOUNT(folder_store)) {
1709 TnyAccount *account = TNY_ACCOUNT(folder_store);
1711 time_t last_updated;
1712 const gchar *last_updated_string;
1713 /* Get last updated from configuration */
1714 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1715 tny_account_get_id (account));
1717 if (last_updated > 0)
1718 last_updated_string = modest_text_utils_get_display_date(last_updated);
1720 last_updated_string = g_strdup (_("mcen_va_never"));
1722 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1723 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1724 label_w = gtk_label_new (NULL);
1725 gtk_label_set_markup (GTK_LABEL (label_w), label);
1726 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1730 g_free (gray_color_markup);
1733 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1739 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1741 ModestMainWindowPrivate *priv = NULL;
1743 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1745 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1747 return priv->send_receive_in_progress;
1751 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1753 GtkAction *action = NULL;
1754 GtkWidget *widget = NULL;
1755 ModestMainWindowPrivate *priv = NULL;
1757 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1758 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1760 priv->send_receive_in_progress = TRUE;
1762 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1763 gtk_action_set_sensitive (action, FALSE);
1764 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1765 /* gtk_action_set_sensitive (action, FALSE); */
1766 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1767 gtk_widget_set_sensitive (widget, FALSE);
1771 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1773 GtkAction *action = NULL;
1774 GtkWidget *widget = NULL;
1775 ModestMainWindowPrivate *priv = NULL;
1777 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1778 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1780 priv->send_receive_in_progress = FALSE;
1782 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1783 gtk_action_set_sensitive (action, TRUE);
1784 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1785 /* gtk_action_set_sensitive (action, TRUE); */
1786 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1787 gtk_widget_set_sensitive (widget, TRUE);
1792 on_msg_count_changed (ModestHeaderView *header_view,
1794 TnyFolderChange *change,
1795 ModestMainWindow *main_window)
1797 gboolean folder_empty = FALSE;
1798 gboolean all_marked_as_deleted = FALSE;
1799 TnyFolderChangeChanged changed;
1800 ModestMainWindowPrivate *priv;
1802 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1803 g_return_if_fail (TNY_IS_FOLDER(folder));
1804 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1805 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1807 changed = tny_folder_change_get_changed (change);
1809 /* If something changes */
1810 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1811 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1813 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1815 /* Check header removed (hide marked as DELETED headers) */
1816 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1817 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1820 /* Check if all messages are marked to be deleted */
1821 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1822 folder_empty = folder_empty || all_marked_as_deleted ;
1824 /* Set contents style of headers view */
1826 modest_main_window_set_contents_style (main_window,
1827 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1828 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1831 modest_main_window_set_contents_style (main_window,
1832 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1838 modest_main_window_set_contents_style (ModestMainWindow *self,
1839 ModestMainWindowContentsStyle style)
1841 ModestMainWindowPrivate *priv;
1843 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1845 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1847 /* We allow to set the same content style than the previously
1848 set if there are details, because it could happen when we're
1849 selecting different accounts consecutively */
1850 if ((priv->contents_style == style) &&
1851 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1854 /* Remove previous child. Delete it if it was an account
1856 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1858 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1859 g_object_ref (content);
1860 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1861 g_object_ref (priv->empty_view);
1862 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1865 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1868 priv->contents_style = style;
1870 switch (priv->contents_style) {
1871 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1872 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1873 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1876 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1878 /* if we're started without main win, there may not be a folder
1879 * view. this fixes a GLib-Critical */
1880 if (priv->folder_view) {
1881 TnyFolderStore *selected_folderstore =
1882 modest_folder_view_get_selected (priv->folder_view);
1883 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1884 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1885 TNY_ACCOUNT (selected_folderstore));
1887 wrap_in_scrolled_window (priv->contents_widget,
1888 priv->details_widget);
1890 g_object_unref (selected_folderstore);
1891 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1896 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1897 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1898 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1902 g_return_if_reached ();
1906 gtk_widget_show_all (priv->contents_widget);
1909 ModestMainWindowContentsStyle
1910 modest_main_window_get_contents_style (ModestMainWindow *self)
1912 ModestMainWindowPrivate *priv;
1914 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1916 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1917 return priv->contents_style;
1922 on_configuration_key_changed (ModestConf* conf,
1924 ModestConfEvent event,
1925 ModestConfNotificationId id,
1926 ModestMainWindow *self)
1928 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1929 TnyAccount *account = NULL;
1931 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1934 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1937 if (priv->folder_view)
1938 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1940 if (account && TNY_IS_ACCOUNT (account) &&
1941 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1944 const gchar *device_name;
1945 gchar *new_text, *gray_color_markup;
1948 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1949 label = GTK_LABEL (children->data);
1951 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1952 MODEST_CONF_DEVICE_NAME, NULL);
1954 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1955 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1957 gtk_label_set_markup (label, new_text);
1958 gtk_widget_show (GTK_WIDGET (label));
1960 g_free (gray_color_markup);
1962 g_list_free (children);
1964 g_object_unref (account);
1968 set_toolbar_transfer_mode (ModestMainWindow *self)
1970 ModestMainWindowPrivate *priv = NULL;
1972 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1974 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1976 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1978 if (priv->progress_bar_timeout > 0) {
1979 g_source_remove (priv->progress_bar_timeout);
1980 priv->progress_bar_timeout = 0;
1987 set_toolbar_mode (ModestMainWindow *self,
1988 ModestToolBarModes mode)
1990 ModestWindowPrivate *parent_priv = NULL;
1991 ModestMainWindowPrivate *priv = NULL;
1992 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1994 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1996 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1997 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1999 /* In case this was called before the toolbar exists: */
2000 if (!(parent_priv->toolbar))
2003 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
2005 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2006 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2007 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2009 /* Sets current toolbar mode */
2010 priv->current_toolbar_mode = mode;
2012 /* Checks the dimming rules */
2013 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2015 /* Show and hide toolbar items */
2017 case TOOLBAR_MODE_NORMAL:
2019 gtk_action_set_visible (sort_action, TRUE);
2021 gtk_action_set_visible (refresh_action, TRUE);
2022 if (priv->progress_toolitem) {
2023 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2024 gtk_widget_hide (priv->progress_toolitem);
2026 if (priv->progress_bar)
2027 gtk_widget_hide (priv->progress_bar);
2030 gtk_action_set_visible (cancel_action, FALSE);
2032 /* Hide toolbar if optimized view is enabled */
2033 if (priv->optimized_view)
2034 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2036 case TOOLBAR_MODE_TRANSFER:
2038 gtk_action_set_visible (sort_action, FALSE);
2040 gtk_action_set_visible (refresh_action, FALSE);
2042 gtk_action_set_visible (cancel_action, TRUE);
2043 if (priv->progress_bar)
2044 gtk_widget_show (priv->progress_bar);
2045 if (priv->progress_toolitem) {
2046 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2047 gtk_widget_show (priv->progress_toolitem);
2050 /* Show toolbar if it's hiden (optimized view ) */
2051 if (priv->optimized_view)
2052 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2055 g_return_if_reached ();
2060 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2062 ModestMainWindowPrivate *priv;
2064 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2065 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2067 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2071 cancel_progressbar (GtkToolButton *toolbutton,
2072 ModestMainWindow *self)
2075 ModestMainWindowPrivate *priv;
2077 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2079 /* Get operation observers and cancel all the operations */
2080 tmp = priv->progress_widgets;
2082 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2083 tmp=g_slist_next(tmp);
2088 observers_empty (ModestMainWindow *self)
2091 ModestMainWindowPrivate *priv;
2092 gboolean is_empty = TRUE;
2093 guint pending_ops = 0;
2095 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2096 tmp = priv->progress_widgets;
2098 /* Check all observers */
2099 while (tmp && is_empty) {
2100 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2101 is_empty = pending_ops == 0;
2103 tmp = g_slist_next(tmp);
2111 * Gets the toolbar mode needed for each mail operation. It stores in
2112 * @mode_changed if the toolbar mode has changed or not
2114 static ModestToolBarModes
2115 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2116 ModestMailOperation *mail_op,
2117 gboolean *mode_changed)
2119 ModestToolBarModes mode;
2120 ModestMainWindowPrivate *priv;
2122 *mode_changed = FALSE;
2123 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2125 /* Get toolbar mode from operation id*/
2126 switch (modest_mail_operation_get_type_operation (mail_op)) {
2127 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2128 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2129 mode = TOOLBAR_MODE_TRANSFER;
2130 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2131 *mode_changed = TRUE;
2134 mode = TOOLBAR_MODE_NORMAL;
2140 on_mail_operation_started (ModestMailOperation *mail_op,
2143 ModestMainWindow *self;
2144 ModestMailOperationTypeOperation op_type;
2145 ModestMainWindowPrivate *priv;
2146 ModestToolBarModes mode;
2148 gboolean mode_changed = FALSE;
2149 TnyAccount *account;
2151 self = MODEST_MAIN_WINDOW (user_data);
2152 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2154 /* Do not show progress for receiving operations if the
2155 account is the local account or the MMC one */
2156 op_type = modest_mail_operation_get_type_operation (mail_op);
2157 account = modest_mail_operation_get_account (mail_op);
2158 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2161 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2162 modest_tny_account_is_memory_card_account (account));
2163 g_object_unref (account);
2168 /* Get toolbar mode from operation id*/
2169 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2171 /* Add operation observers and change toolbar if neccessary*/
2172 tmp = priv->progress_widgets;
2173 if (mode == TOOLBAR_MODE_TRANSFER) {
2175 set_toolbar_transfer_mode(self);
2178 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2180 tmp = g_slist_next (tmp);
2186 on_mail_operation_finished (ModestMailOperation *mail_op,
2189 ModestToolBarModes mode;
2190 ModestMailOperationTypeOperation op_type;
2192 ModestMainWindow *self;
2193 gboolean mode_changed;
2194 TnyAccount *account;
2195 ModestMainWindowPrivate *priv;
2197 self = MODEST_MAIN_WINDOW (user_data);
2198 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2200 /* The mail operation was not added to the progress objects if
2201 the account was the local account or the MMC one */
2202 op_type = modest_mail_operation_get_type_operation (mail_op);
2203 account = modest_mail_operation_get_account (mail_op);
2204 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2207 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2208 modest_tny_account_is_memory_card_account (account));
2209 g_object_unref (account);
2214 /* Get toolbar mode from operation id*/
2215 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2217 /* Change toolbar mode */
2218 tmp = priv->progress_widgets;
2219 if (mode == TOOLBAR_MODE_TRANSFER) {
2221 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2223 tmp = g_slist_next (tmp);
2226 /* If no more operations are being observed, NORMAL mode is enabled again */
2227 if (observers_empty (self)) {
2228 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2234 on_queue_changed (ModestMailOperationQueue *queue,
2235 ModestMailOperation *mail_op,
2236 ModestMailOperationQueueNotification type,
2237 ModestMainWindow *self)
2239 ModestMainWindowPrivate *priv;
2241 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2243 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2244 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2246 "operation-started",
2247 G_CALLBACK (on_mail_operation_started),
2249 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2251 "operation-finished",
2252 G_CALLBACK (on_mail_operation_finished),
2254 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2255 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2257 "operation-started");
2258 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2260 "operation-finished");
2265 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2267 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2270 /* Get account data */
2271 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2272 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2274 /* Set the new visible & active account */
2275 if (acc_data && acc_data->store_account) {
2276 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2277 acc_data->store_account->account_name);
2278 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2279 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2280 if (action != NULL) {
2281 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2282 modest_maemo_toggle_action_set_active_block_notify (
2283 GTK_TOGGLE_ACTION (action),
2289 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2294 modest_account_mgr_free_account_data (mgr, acc_data);
2297 /* Make sure that at least one account is "viewed": */
2299 set_at_least_one_account_visible(ModestMainWindow *self)
2301 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2302 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2304 if (!(priv->folder_view)) {
2305 /* It is too early to do this. */
2309 const gchar *active_server_account_name =
2310 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2312 if (!active_server_account_name ||
2313 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2315 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2316 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2317 if (default_modest_name) {
2318 set_account_visible (self, default_modest_name);
2319 } else if (first_modest_name) {
2320 set_account_visible (self, first_modest_name);
2322 g_free (first_modest_name);
2323 g_free (default_modest_name);
2328 on_show_account_action_toggled (GtkToggleAction *action,
2331 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2333 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2334 if (gtk_toggle_action_get_active (action))
2335 set_account_visible (self, acc_name);
2339 refresh_account (const gchar *account_name)
2343 /* win must already exists here, obviously */
2344 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2347 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2351 /* If account_name == NULL, we must update all (option All) */
2353 modest_ui_actions_do_send_receive_all (win);
2355 modest_ui_actions_do_send_receive (account_name, win);
2360 on_refresh_account_action_activated (GtkAction *action,
2363 refresh_account ((const gchar*) user_data);
2367 on_send_receive_csm_activated (GtkMenuItem *item,
2370 refresh_account ((const gchar*) user_data);
2374 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2376 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2378 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2384 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2386 ModestMainWindow *main_window = NULL;
2388 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2389 main_window = MODEST_MAIN_WINDOW (userdata);
2391 /* Update toolbar dimming state */
2392 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2398 on_header_view_focus_in (GtkWidget *widget,
2399 GdkEventFocus *event,
2402 ModestMainWindow *main_window = NULL;
2404 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2406 main_window = MODEST_MAIN_WINDOW (userdata);
2408 /* Update toolbar dimming state */
2409 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2415 on_folder_selection_changed (ModestFolderView *folder_view,
2416 TnyFolderStore *folder_store,
2418 ModestMainWindow *main_window)
2420 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2421 GtkAction *action = NULL;
2422 gboolean show_reply = TRUE;
2423 gboolean show_forward = TRUE;
2424 gboolean show_cancel_send = FALSE;
2425 gboolean show_clipboard = TRUE;
2426 gboolean show_delete = TRUE;
2429 if (TNY_IS_ACCOUNT (folder_store)) {
2430 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2431 } else if (TNY_IS_FOLDER (folder_store)) {
2432 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2433 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2434 TNY_FOLDER (folder_store));
2435 switch (folder_type) {
2436 case TNY_FOLDER_TYPE_DRAFTS:
2437 show_clipboard = show_delete = TRUE;
2438 show_reply = show_forward = show_cancel_send = FALSE;
2440 case TNY_FOLDER_TYPE_SENT:
2441 show_forward = show_clipboard = show_delete = TRUE;
2442 show_reply = show_cancel_send = FALSE;
2444 case TNY_FOLDER_TYPE_OUTBOX:
2445 show_clipboard = show_delete = show_cancel_send = TRUE;
2446 show_reply = show_forward = FALSE;
2448 case TNY_FOLDER_TYPE_INVALID:
2449 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2452 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2453 show_cancel_send = FALSE;
2456 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2457 show_cancel_send = FALSE;
2462 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2463 gtk_action_set_visible (action, show_reply);
2464 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2465 gtk_action_set_visible (action, show_reply);
2466 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2467 gtk_action_set_visible (action, show_forward);
2468 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2469 gtk_action_set_visible (action, show_cancel_send);
2470 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2471 gtk_action_set_visible (action, show_delete);
2473 /* We finally call to the ui actions handler, after updating properly
2474 * the header view CSM */
2475 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2479 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2480 GtkTreeModel *model,
2481 GtkTreeRowReference *row_reference,
2482 ModestMainWindow *self)
2484 ModestMainWindowPrivate *priv = NULL;
2485 GtkTreeModel *header_model = NULL;
2486 GtkTreePath *path = NULL;
2488 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2489 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2490 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2492 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2493 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2495 /* Do nothing if we changed the folder in the main view */
2496 if (header_model != model)
2499 /* Select the message in the header view */
2500 path = gtk_tree_row_reference_get_path (row_reference);
2501 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2503 gtk_tree_path_free (path);
2509 show_updating_banner (gpointer user_data)
2511 ModestMainWindowPrivate *priv = NULL;
2513 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2515 if (priv->updating_banner == NULL) {
2517 /* We're outside the main lock */
2518 gdk_threads_enter ();
2519 priv->updating_banner =
2520 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2521 _CS ("ckdg_pb_updating"));
2522 gdk_threads_leave ();
2525 /* Remove timeout */
2526 priv->updating_banner_timeout = 0;
2531 * We use this function to show/hide a progress banner showing
2532 * "Updating" while the header view is being filled. We're not showing
2533 * it unless the update takes more than 2 seconds
2535 * If starting = TRUE then the refresh is starting, otherwise it means
2536 * that is has just finished
2539 on_updating_msg_list (ModestHeaderView *header_view,
2543 ModestMainWindowPrivate *priv = NULL;
2545 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2547 /* Remove old timeout */
2548 if (priv->updating_banner_timeout > 0) {
2549 g_source_remove (priv->updating_banner_timeout);
2550 priv->updating_banner_timeout = 0;
2553 /* Create a new timeout */
2555 priv->updating_banner_timeout =
2556 g_timeout_add (2000, show_updating_banner, user_data);
2558 /* Remove the banner if exists */
2559 if (priv->updating_banner) {
2560 gtk_widget_destroy (priv->updating_banner);
2561 priv->updating_banner = NULL;