1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-maemo-utils.h>
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-mail-operation.h"
60 #include "modest-icon-names.h"
61 #include "modest-progress-bar-widget.h"
62 #include "modest-text-utils.h"
63 #include "modest-ui-dimming-manager.h"
64 #include "maemo/modest-osso-state-saving.h"
65 #include "modest-text-utils.h"
66 #include "modest-signal-mgr.h"
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-program.h>
71 #include <hildon/hildon-program.h>
72 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
74 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
81 /* 'private'/'protected' functions */
82 static void modest_main_window_class_init (ModestMainWindowClass *klass);
83 static void modest_main_window_init (ModestMainWindow *obj);
84 static void modest_main_window_finalize (GObject *obj);
86 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
87 GdkEventWindowState *event,
90 static void connect_signals (ModestMainWindow *self);
92 static void modest_main_window_disconnect_signals (ModestWindow *self);
94 static void restore_settings (ModestMainWindow *self,
95 gboolean do_folder_view_too);
97 static void save_state (ModestWindow *self);
99 static void update_menus (ModestMainWindow* self);
101 static void modest_main_window_show_toolbar (ModestWindow *window,
102 gboolean show_toolbar);
104 static void cancel_progressbar (GtkToolButton *toolbutton,
105 ModestMainWindow *self);
107 static void on_queue_changed (ModestMailOperationQueue *queue,
108 ModestMailOperation *mail_op,
109 ModestMailOperationQueueNotification type,
110 ModestMainWindow *self);
112 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
115 on_account_inserted (TnyAccountStore *accoust_store,
120 on_account_removed (TnyAccountStore *accoust_store,
124 static void on_default_account_changed (ModestAccountMgr* mgr,
127 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
131 static void on_configuration_key_changed (ModestConf* conf,
133 ModestConfEvent event,
134 ModestConfNotificationId id,
135 ModestMainWindow *self);
137 static void set_toolbar_mode (ModestMainWindow *self,
138 ModestToolBarModes mode);
140 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
142 static void on_show_account_action_toggled (GtkToggleAction *action,
145 static void on_refresh_account_action_activated (GtkAction *action,
148 static void on_send_receive_csm_activated (GtkMenuItem *item,
151 static void on_msg_count_changed (ModestHeaderView *header_view,
153 TnyFolderChange *change,
154 ModestMainWindow *main_window);
156 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
159 static GtkWidget * create_empty_view (void);
161 static gboolean on_folder_view_focus_in (GtkWidget *widget,
162 GdkEventFocus *event,
165 static gboolean on_header_view_focus_in (GtkWidget *widget,
166 GdkEventFocus *event,
169 static void modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
170 TnyFolderStore *folder_store,
172 ModestMainWindow *main_window);
174 static void set_at_least_one_account_visible(ModestMainWindow *self);
176 static void on_updating_msg_list (ModestHeaderView *header_view,
180 static gboolean restore_paned_timeout_handler (gpointer *data);
182 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
183 struct _ModestMainWindowPrivate {
184 GtkWidget *msg_paned;
185 GtkWidget *main_paned;
186 GtkWidget *main_vbox;
187 GtkWidget *contents_widget;
188 GtkWidget *empty_view;
190 /* Progress observers */
191 GtkWidget *progress_bar;
192 GSList *progress_widgets;
195 GtkWidget *progress_toolitem;
196 GtkWidget *cancel_toolitem;
197 GtkWidget *sort_toolitem;
198 GtkWidget *refresh_toolitem;
199 ModestToolBarModes current_toolbar_mode;
201 /* Merge ids used to add/remove accounts to the ViewMenu*/
202 GByteArray *merge_ids;
203 GtkActionGroup *view_additions_group;
205 /* On-demand widgets */
206 GtkWidget *accounts_popup;
207 GtkWidget *details_widget;
209 /* Optimized view enabled */
210 gboolean optimized_view;
212 /* Optimized view enabled */
213 gboolean send_receive_in_progress;
215 ModestHeaderView *header_view;
216 ModestFolderView *folder_view;
218 ModestMainWindowStyle style;
219 ModestMainWindowContentsStyle contents_style;
221 guint progress_bar_timeout;
222 guint restore_paned_timeout;
224 /* Signal handler UIDs */
225 GList *queue_err_signals;
228 /* "Updating" banner for header view */
229 GtkWidget *updating_banner;
230 guint updating_banner_timeout;
232 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
233 MODEST_TYPE_MAIN_WINDOW, \
234 ModestMainWindowPrivate))
236 typedef struct _GetMsgAsyncHelper {
237 ModestMainWindowPrivate *main_window_private;
239 ModestTnyMsgReplyType reply_type;
240 ModestTnyMsgForwardType forward_type;
247 static GtkWindowClass *parent_class = NULL;
250 /* Private actions */
251 /* This is the context sensitive menu: */
252 static const GtkActionEntry modest_folder_view_action_entries [] = {
254 /* Folder View CSM actions */
255 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
256 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
257 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
258 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
259 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
260 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
263 static const GtkActionEntry modest_header_view_action_entries [] = {
265 /* Header View CSM actions */
266 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
267 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
268 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
269 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
270 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
271 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
272 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
273 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
274 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
275 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
278 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
279 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
282 /************************************************************************/
285 modest_main_window_get_type (void)
287 static GType my_type = 0;
289 static const GTypeInfo my_info = {
290 sizeof(ModestMainWindowClass),
291 NULL, /* base init */
292 NULL, /* base finalize */
293 (GClassInitFunc) modest_main_window_class_init,
294 NULL, /* class finalize */
295 NULL, /* class data */
296 sizeof(ModestMainWindow),
298 (GInstanceInitFunc) modest_main_window_init,
301 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
309 modest_main_window_class_init (ModestMainWindowClass *klass)
311 GObjectClass *gobject_class;
312 gobject_class = (GObjectClass*) klass;
313 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
315 parent_class = g_type_class_peek_parent (klass);
316 gobject_class->finalize = modest_main_window_finalize;
318 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
320 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
321 modest_window_class->save_state_func = save_state;
322 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
323 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
324 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
328 modest_main_window_init (ModestMainWindow *obj)
330 ModestMainWindowPrivate *priv;
332 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
334 priv->queue_err_signals = NULL;
335 priv->msg_paned = NULL;
336 priv->main_paned = NULL;
337 priv->main_vbox = NULL;
338 priv->header_view = NULL;
339 priv->folder_view = NULL;
340 priv->contents_widget = NULL;
341 priv->accounts_popup = NULL;
342 priv->details_widget = NULL;
343 priv->empty_view = NULL;
344 priv->progress_widgets = NULL;
345 priv->progress_bar = NULL;
346 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
347 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
348 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
349 priv->merge_ids = NULL;
350 priv->optimized_view = FALSE;
351 priv->send_receive_in_progress = FALSE;
352 priv->progress_bar_timeout = 0;
353 priv->restore_paned_timeout = 0;
354 priv->sighandlers = NULL;
355 priv->updating_banner = NULL;
356 priv->updating_banner_timeout = 0;
358 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
360 "applications_email_mainview");
364 modest_main_window_finalize (GObject *obj)
366 ModestMainWindowPrivate *priv;
368 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
370 /* Sanity check: shouldn't be needed, the window mgr should
371 call this function before */
372 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
374 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
376 g_slist_free (priv->progress_widgets);
378 g_byte_array_free (priv->merge_ids, TRUE);
380 if (priv->progress_bar_timeout > 0) {
381 g_source_remove (priv->progress_bar_timeout);
382 priv->progress_bar_timeout = 0;
385 if (priv->updating_banner_timeout > 0) {
386 g_source_remove (priv->updating_banner_timeout);
387 priv->updating_banner_timeout = 0;
390 if (priv->updating_banner) {
391 gtk_widget_destroy (priv->updating_banner);
392 priv->updating_banner = NULL;
395 if (priv->restore_paned_timeout > 0) {
396 g_source_remove (priv->restore_paned_timeout);
397 priv->restore_paned_timeout = 0;
400 G_OBJECT_CLASS(parent_class)->finalize (obj);
404 modest_main_window_get_child_widget (ModestMainWindow *self,
405 ModestMainWindowWidgetType widget_type)
407 ModestMainWindowPrivate *priv;
410 g_return_val_if_fail (self, NULL);
411 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
414 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
416 switch (widget_type) {
417 case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
418 widget = (GtkWidget*)priv->header_view; break;
419 case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
420 widget = (GtkWidget*)priv->folder_view; break;
425 return widget ? GTK_WIDGET(widget) : NULL;
429 restore_paned_timeout_handler (gpointer *data)
431 ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
432 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
435 /* Timeouts are outside the main lock */
436 gdk_threads_enter ();
437 if (GTK_WIDGET_VISIBLE (main_window)) {
438 conf = modest_runtime_get_conf ();
439 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
440 MODEST_CONF_MAIN_PANED_KEY);
442 gdk_threads_leave ();
449 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
452 ModestMainWindowPrivate *priv;
454 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
456 conf = modest_runtime_get_conf ();
458 modest_widget_memory_restore (conf, G_OBJECT(self),
459 MODEST_CONF_MAIN_WINDOW_KEY);
461 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
462 MODEST_CONF_HEADER_VIEW_KEY);
464 if (do_folder_view_too)
465 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
466 MODEST_CONF_FOLDER_VIEW_KEY);
468 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
469 MODEST_CONF_MAIN_PANED_KEY);
471 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
473 /* We need to force a redraw here in order to get the right
474 position of the horizontal paned separator */
475 gtk_widget_show (GTK_WIDGET (self));
480 save_state (ModestWindow *window)
483 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
484 ModestMainWindowPrivate *priv;
486 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
487 conf = modest_runtime_get_conf ();
489 modest_widget_memory_save (conf,G_OBJECT(self),
490 MODEST_CONF_MAIN_WINDOW_KEY);
491 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
492 MODEST_CONF_MAIN_PANED_KEY);
493 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
494 // MODEST_CONF_HEADER_VIEW_KEY);
495 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
496 MODEST_CONF_FOLDER_VIEW_KEY);
500 compare_display_names (ModestAccountData *a,
501 ModestAccountData *b)
503 return strcmp (a->display_name, b->display_name);
507 update_menus (ModestMainWindow* self)
509 GSList *account_names, *iter, *accounts;
510 ModestMainWindowPrivate *priv;
511 ModestWindowPrivate *parent_priv;
512 ModestAccountMgr *mgr;
513 gint i, num_accounts;
515 gchar *default_account;
516 const gchar *active_account_name;
517 GtkWidget *send_receive_button, *item;
518 GtkAction *send_receive_all = NULL;
521 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
522 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
524 /* Get enabled account IDs */
525 mgr = modest_runtime_get_account_mgr ();
526 account_names = modest_account_mgr_account_names (mgr, TRUE);
527 iter = account_names;
531 ModestAccountData *account_data =
532 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
533 accounts = g_slist_prepend (accounts, account_data);
537 modest_account_mgr_free_account_names (account_names);
538 account_names = NULL;
540 /* Order the list of accounts by its display name */
541 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
542 num_accounts = g_slist_length (accounts);
544 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
545 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
546 gtk_action_set_visible (send_receive_all, num_accounts > 1);
548 /* Delete old send&receive popup items. We can not just do a
549 menu_detach because it does not work well with
551 if (priv->accounts_popup)
552 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
553 (GtkCallback) gtk_widget_destroy, NULL);
555 /* Delete old entries in the View menu. Do not free groups, it
557 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
559 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
560 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
561 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
562 GTK_ACTION_GROUP (groups->data));
565 if (priv->merge_ids) {
566 for (i = 0; i < priv->merge_ids->len; i++)
567 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
568 g_byte_array_free (priv->merge_ids, TRUE);
570 /* We need to call this in order to ensure
571 that the new actions are added in the right
572 order (alphabetical) */
573 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
575 groups = g_list_next (groups);
577 priv->merge_ids = g_byte_array_sized_new (num_accounts);
579 /* Get send receive button */
580 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
581 "/ToolBar/ToolbarSendReceive");
583 /* Create the menu */
584 if (num_accounts > 1) {
585 if (!priv->accounts_popup)
586 priv->accounts_popup = gtk_menu_new ();
587 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
588 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
589 g_signal_connect (G_OBJECT (item),
591 G_CALLBACK (on_send_receive_csm_activated),
593 item = gtk_separator_menu_item_new ();
594 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
597 /* Create a new action group */
598 default_account = modest_account_mgr_get_default_account (mgr);
599 active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
601 if (!active_account_name)
602 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
604 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
606 for (i = 0; i < num_accounts; i++) {
607 gchar *display_name = NULL;
608 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
611 g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
615 if (default_account && account_data->account_name &&
616 !(strcmp (default_account, account_data->account_name) == 0)) {
617 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
618 account_data->display_name);
620 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
621 account_data->display_name);
624 /* Create action and add it to the action group. The
625 action name must be the account name, this way we
626 could know in the handlers the account to show */
627 if (account_data && account_data->account_name) {
628 gchar* item_name, *refresh_action_name;
630 GtkAction *view_account_action, *refresh_account_action;
632 view_account_action = GTK_ACTION (gtk_radio_action_new (account_data->account_name,
633 display_name, NULL, NULL, 0));
634 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
635 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
636 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
638 if (active_account_name) {
639 if (active_account_name && account_data->account_name &&
640 (strcmp (active_account_name, account_data->account_name) == 0)) {
641 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
645 /* Add ui from account data. We allow 2^9-1 account
646 changes in a single execution because we're
647 downcasting the guint to a guint8 in order to use a
648 GByteArray. It should be enough. */
649 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
650 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
651 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
652 gtk_ui_manager_add_ui (parent_priv->ui_manager,
654 "/MenuBar/ViewMenu/ViewMenuAdditions",
656 account_data->account_name,
657 GTK_UI_MANAGER_MENUITEM,
660 /* Connect the action signal "activate" */
661 g_signal_connect_after (G_OBJECT (view_account_action),
663 G_CALLBACK (on_show_account_action_toggled),
666 /* Create the items for the Tools->Send&Receive submenu */
667 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
668 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
669 display_name, NULL, NULL);
670 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
672 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
673 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
674 gtk_ui_manager_add_ui (parent_priv->ui_manager,
676 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
679 GTK_UI_MANAGER_MENUITEM,
681 g_free (refresh_action_name);
683 g_signal_connect_data (G_OBJECT (refresh_account_action),
685 G_CALLBACK (on_refresh_account_action_activated),
686 g_strdup (account_data->account_name),
687 (GClosureNotify) g_free,
690 /* Create item and add it to the send&receive
691 CSM. If there is only one account then
693 if (priv->accounts_popup) {
694 GtkWidget *label = gtk_label_new(NULL);
695 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
696 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
698 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
699 gtk_label_set_markup (GTK_LABEL (label), escaped);
704 gtk_label_set_text (GTK_LABEL (label), display_name);
707 item = gtk_menu_item_new ();
708 gtk_container_add (GTK_CONTAINER (item), label);
710 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
711 g_signal_connect_data (G_OBJECT (item),
713 G_CALLBACK (on_send_receive_csm_activated),
714 g_strdup (account_data->account_name),
715 (GClosureNotify) g_free,
722 g_free (display_name);
725 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
727 /* We cannot do this in the loop above because this relies on the action
728 * group being inserted. This makes the default account appear in bold.
729 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
730 for (i = 0; i < num_accounts; i++) {
731 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
733 if(account_data->account_name && default_account &&
734 strcmp (account_data->account_name, default_account) == 0) {
735 gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
737 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
738 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
742 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
743 if (GTK_IS_LABEL (child)) {
744 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
745 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
746 gtk_label_set_markup (GTK_LABEL (child), bold_name);
751 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
752 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
756 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
757 if (GTK_IS_LABEL (child)) {
758 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
759 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
760 gtk_label_set_markup (GTK_LABEL (child), bold_name);
768 modest_account_mgr_free_account_data (mgr, account_data);
771 if (priv->accounts_popup) {
772 /* Mandatory in order to view the menu contents */
773 gtk_widget_show_all (priv->accounts_popup);
775 /* Setup tap_and_hold just if was not done before*/
776 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
777 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
781 g_slist_free (accounts);
782 g_free (default_account);
785 /* Make sure that at least one account is viewed if there are any
786 * accounts, for instance when adding the first account: */
787 set_at_least_one_account_visible (self);
791 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
793 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
794 gtk_scrolled_window_add_with_viewport
795 (GTK_SCROLLED_WINDOW(win), widget);
797 gtk_container_add (GTK_CONTAINER(win),
808 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
810 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
812 GList *oerrsignals = priv->queue_err_signals;
813 while (oerrsignals) {
814 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
815 g_signal_handler_disconnect (esignal->queue, esignal->signal);
816 g_slice_free (QueueErrorSignal, esignal);
817 oerrsignals = g_list_next (oerrsignals);
819 g_list_free (priv->queue_err_signals);
820 priv->queue_err_signals = NULL;
825 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
827 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
830 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
834 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
836 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
838 /* Update visibility */
841 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
845 modest_main_window_disconnect_signals (ModestWindow *self)
847 ModestMainWindowPrivate *priv;
848 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
850 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
851 priv->sighandlers = NULL;
855 connect_signals (ModestMainWindow *self)
857 ModestWindowPrivate *parent_priv;
858 ModestMainWindowPrivate *priv;
861 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
862 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
867 modest_signal_mgr_connect (priv->sighandlers,
868 G_OBJECT(priv->folder_view), "key-press-event",
869 G_CALLBACK(on_inner_widgets_key_pressed), self);
871 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "folder_selection_changed",
872 G_CALLBACK (modest_main_window_on_folder_selection_changed), self);
874 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
875 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), self);
877 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event",
878 G_CALLBACK (on_folder_view_focus_in), self);
880 /* Folder view CSM */
881 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
882 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
883 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
884 G_CALLBACK(_folder_view_csm_menu_activated),
888 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
889 G_CALLBACK(modest_ui_actions_on_header_selected), self);
891 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
892 G_CALLBACK(modest_ui_actions_on_header_activated), self);
894 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
895 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
897 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
898 G_CALLBACK(on_inner_widgets_key_pressed), self);
900 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
901 G_CALLBACK(on_msg_count_changed), self);
903 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
904 G_CALLBACK (on_header_view_focus_in), self);
906 modest_signal_mgr_connect (priv->sighandlers,
907 G_OBJECT (priv->header_view),
909 G_CALLBACK (on_updating_msg_list),
912 /* Header view CSM */
913 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
914 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
916 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
917 G_CALLBACK(_header_view_csm_menu_activated),
922 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
923 G_CALLBACK (modest_main_window_window_state_event),
926 /* Mail Operation Queue */
928 modest_signal_mgr_connect (priv->sighandlers,
929 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
931 G_CALLBACK (on_queue_changed), self);
933 /* Track changes in the device name */
935 modest_signal_mgr_connect (priv->sighandlers,
936 G_OBJECT(modest_runtime_get_conf ()),
938 G_CALLBACK (on_configuration_key_changed),
941 /* Track account changes. We need to refresh the toolbar */
943 modest_signal_mgr_connect (priv->sighandlers,
944 G_OBJECT (modest_runtime_get_account_store ()),
946 G_CALLBACK (on_account_inserted),
949 modest_signal_mgr_connect (priv->sighandlers,
950 G_OBJECT (modest_runtime_get_account_store ()),
952 G_CALLBACK (on_account_removed),
955 /* We need to refresh the send & receive menu to change the bold
956 * account when the default account changes. */
958 modest_signal_mgr_connect (priv->sighandlers,
959 G_OBJECT (modest_runtime_get_account_mgr ()),
960 "default_account_changed",
961 G_CALLBACK (on_default_account_changed),
966 modest_signal_mgr_connect (priv->sighandlers,
967 G_OBJECT (modest_runtime_get_account_store()),
968 "password_requested",
969 G_CALLBACK (modest_ui_actions_on_password_requested),
974 /** Idle handler, to send/receive at startup .*/
976 sync_accounts_cb (ModestMainWindow *win)
978 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
979 return FALSE; /* Do not call this idle handler again. */
984 on_hildon_program_is_topmost_notify(GObject *self,
985 GParamSpec *propert_param, gpointer user_data)
987 HildonProgram *app = HILDON_PROGRAM (self);
990 ModestWindow* self = MODEST_WINDOW(user_data);
993 /* Note that use of hildon_program_set_can_hibernate()
994 * is generally referred to as "setting the killable flag",
995 * though hibernation does not seem equal to death.
998 if (hildon_program_get_is_topmost (app)) {
999 /* Prevent hibernation when the progam comes to the foreground,
1000 * because hibernation should only happen when the application
1001 * is in the background: */
1002 hildon_program_set_can_hibernate (app, FALSE);
1004 /* Allow hibernation if the program has gone to the background: */
1006 /* However, prevent hibernation while the settings are being changed: */
1007 const gboolean hibernation_prevented =
1008 modest_window_mgr_get_hibernation_is_prevented (
1009 modest_runtime_get_window_mgr ());
1011 if (hibernation_prevented)
1012 hildon_program_set_can_hibernate (app, FALSE);
1014 /* Allow hibernation, after saving the state: */
1015 modest_osso_save_state();
1016 hildon_program_set_can_hibernate (app, TRUE);
1023 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1025 GtkWidget *folder_win = (GtkWidget *) user_data;
1026 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1028 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1029 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1031 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1033 /* Connect signals */
1034 connect_signals (MODEST_MAIN_WINDOW (self));
1036 /* Set account store */
1037 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1038 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1040 /* Load previous osso state, for instance if we are being restored from
1042 modest_osso_load_state ();
1044 /* Restore window & widget settings */
1045 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1047 /* Check if accounts exist and show the account wizard if not */
1048 gboolean accounts_exist =
1049 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1051 if (!accounts_exist) {
1052 /* This is necessary to have the main window shown behind the dialog
1053 It's an ugly hack... jschmid */
1054 gtk_widget_show_all(GTK_WIDGET(self));
1055 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1058 GtkAction *send_receive_all;
1059 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1060 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1061 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1062 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1063 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1064 modest_account_mgr_free_account_names (accounts);
1065 update_menus (MODEST_MAIN_WINDOW (self));
1070 modest_main_window_new (void)
1072 ModestMainWindow *self = NULL;
1073 ModestMainWindowPrivate *priv = NULL;
1074 ModestWindowPrivate *parent_priv = NULL;
1075 GtkWidget *folder_win = NULL;
1076 ModestDimmingRulesGroup *menu_rules_group = NULL;
1077 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1078 GtkActionGroup *action_group = NULL;
1079 GError *error = NULL;
1080 ModestConf *conf = NULL;
1081 GtkAction *action = NULL;
1082 GdkPixbuf *window_icon;
1084 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1085 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1086 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1088 parent_priv->ui_manager = gtk_ui_manager_new();
1089 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1091 action_group = gtk_action_group_new ("ModestMainWindowActions");
1092 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1094 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1095 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1097 /* Add common actions */
1098 gtk_action_group_add_actions (action_group,
1099 modest_action_entries,
1100 G_N_ELEMENTS (modest_action_entries),
1103 gtk_action_group_add_actions (action_group,
1104 modest_folder_view_action_entries,
1105 G_N_ELEMENTS (modest_folder_view_action_entries),
1108 gtk_action_group_add_actions (action_group,
1109 modest_header_view_action_entries,
1110 G_N_ELEMENTS (modest_header_view_action_entries),
1113 gtk_action_group_add_toggle_actions (action_group,
1114 modest_toggle_action_entries,
1115 G_N_ELEMENTS (modest_toggle_action_entries),
1118 gtk_action_group_add_toggle_actions (action_group,
1119 modest_main_window_toggle_action_entries,
1120 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1123 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1124 g_object_unref (action_group);
1126 /* Load the UI definition */
1127 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1128 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1129 if (error != NULL) {
1130 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1131 g_error_free (error);
1135 /* Add common dimming rules */
1136 modest_dimming_rules_group_add_rules (menu_rules_group,
1137 modest_main_window_menu_dimming_entries,
1138 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1139 MODEST_WINDOW (self));
1140 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1141 modest_main_window_toolbar_dimming_entries,
1142 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1143 MODEST_WINDOW (self));
1145 /* Insert dimming rules group for this window */
1146 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1147 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1148 g_object_unref (menu_rules_group);
1149 g_object_unref (toolbar_rules_group);
1151 /* Add accelerators */
1152 gtk_window_add_accel_group (GTK_WINDOW (self),
1153 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1155 /* Menubar. Update the state of some toggles */
1156 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1157 conf = modest_runtime_get_conf ();
1158 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1159 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1160 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1161 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1162 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1163 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1164 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1165 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1166 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1167 gtk_widget_show (parent_priv->menubar);
1169 /* Get device name */
1170 modest_maemo_utils_get_device_name ();
1174 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1175 if (!priv->header_view)
1176 g_printerr ("modest: cannot instantiate header view\n");
1177 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1178 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1179 MODEST_CONF_HEADER_VIEW_KEY);
1181 /* Other style properties of header view */
1182 g_object_set (G_OBJECT (priv->header_view),
1183 "rules-hint", FALSE,
1185 /* gtk_widget_show (priv->header_view); */
1188 priv->empty_view = create_empty_view ();
1189 gtk_widget_show (priv->empty_view);
1191 /* Create scrolled windows */
1192 folder_win = gtk_scrolled_window_new (NULL, NULL);
1193 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1194 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1196 GTK_POLICY_AUTOMATIC);
1197 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1199 GTK_POLICY_AUTOMATIC);
1200 /* gtk_widget_show (priv->contents_widget); */
1203 priv->main_paned = gtk_hpaned_new ();
1204 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1205 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1206 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1208 /* putting it all together... */
1209 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1210 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1211 gtk_widget_show (priv->main_vbox);
1213 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1215 HildonProgram *app = hildon_program_get_instance ();
1216 hildon_program_add_window (app, HILDON_WINDOW (self));
1218 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1219 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1221 g_signal_connect (G_OBJECT(self), "show",
1222 G_CALLBACK (modest_main_window_on_show), folder_win);
1224 /* Set window icon */
1225 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1227 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1228 g_object_unref (window_icon);
1231 /* Dont't restore settings here,
1232 * because it requires a gtk_widget_show(),
1233 * and we don't want to do that until later,
1234 * so that the UI is not visible for non-menu D-Bus activation.
1236 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1238 return MODEST_WINDOW(self);
1242 modest_main_window_set_style (ModestMainWindow *self,
1243 ModestMainWindowStyle style)
1245 ModestMainWindowPrivate *priv;
1246 ModestWindowPrivate *parent_priv;
1250 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1252 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1253 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1255 /* no change -> nothing to do */
1256 if (priv->style == style)
1259 /* Get toggle button and update the state if needed. This will
1260 happen only when the set_style is not invoked from the UI,
1261 for example when it's called from widget memory */
1262 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1263 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1264 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1265 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1266 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1267 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1268 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1271 priv->style = style;
1273 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1274 /* Remove main paned */
1275 g_object_ref (priv->main_paned);
1276 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1278 /* Reparent the contents widget to the main vbox */
1279 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1282 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1283 /* Remove header view */
1284 g_object_ref (priv->contents_widget);
1285 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1287 /* Reparent the main paned */
1288 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1289 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1293 g_return_if_reached ();
1296 /* Let header view grab the focus if it's being shown */
1297 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1298 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1300 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1303 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1306 ModestMainWindowStyle
1307 modest_main_window_get_style (ModestMainWindow *self)
1309 ModestMainWindowPrivate *priv;
1311 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1313 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1320 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1322 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1323 ModestWindowPrivate *parent_priv;
1324 ModestWindowMgr *mgr;
1325 gboolean is_fullscreen;
1326 GtkAction *fs_toggle_action;
1329 mgr = modest_runtime_get_window_mgr ();
1331 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1333 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1335 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1336 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1337 if (is_fullscreen != active) {
1338 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1347 set_homogeneous (GtkWidget *widget,
1350 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1351 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1355 modest_main_window_show_toolbar (ModestWindow *self,
1356 gboolean show_toolbar)
1358 ModestMainWindowPrivate *priv = NULL;
1359 ModestWindowPrivate *parent_priv = NULL;
1360 GtkWidget *reply_button = NULL, *menu = NULL;
1361 GtkWidget *placeholder = NULL;
1363 const gchar *action_name;
1366 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1367 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1368 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1370 /* Set optimized view status */
1371 priv->optimized_view = !show_toolbar;
1373 if (!parent_priv->toolbar) {
1374 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1376 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1378 /* Set homogeneous toolbar */
1379 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1380 set_homogeneous, NULL);
1382 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1383 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1384 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1385 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1386 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1387 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1388 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1389 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1391 /* Add ProgressBar (Transfer toolbar) */
1392 priv->progress_bar = modest_progress_bar_widget_new ();
1393 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1394 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1395 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1396 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1397 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1399 /* Connect cancel 'clicked' signal to abort progress mode */
1400 g_signal_connect(priv->cancel_toolitem, "clicked",
1401 G_CALLBACK(cancel_progressbar),
1404 /* Add it to the observers list */
1405 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1408 hildon_window_add_toolbar (HILDON_WINDOW (self),
1409 GTK_TOOLBAR (parent_priv->toolbar));
1411 /* Set reply button tap and hold menu */
1412 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1413 "/ToolBar/ToolbarMessageReply");
1414 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1415 "/ToolbarReplyCSM");
1416 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1418 /* Set send & receive button tap and hold menu */
1419 update_menus (MODEST_MAIN_WINDOW (self));
1423 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1424 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1425 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1427 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1428 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1430 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1434 /* Update also the actions (to update the toggles in the
1435 menus), we have to do it manually because some other window
1436 of the same time could have changed it (remember that the
1437 toolbar fullscreen mode is shared by all the windows of the
1439 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1440 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1442 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1444 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1445 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1450 on_account_inserted (TnyAccountStore *accoust_store,
1451 TnyAccount *account,
1454 update_menus (MODEST_MAIN_WINDOW (user_data));
1458 on_default_account_changed (ModestAccountMgr* mgr,
1461 update_menus (MODEST_MAIN_WINDOW (user_data));
1465 on_account_removed (TnyAccountStore *accoust_store,
1466 TnyAccount *account,
1469 update_menus (MODEST_MAIN_WINDOW (user_data));
1473 * This function manages the key events used to navigate between
1474 * header and folder views (when the window is in split view)
1477 * -------------------------------------------------
1478 * HeaderView GDK_Left Move focus to folder view
1479 * FolderView GDK_Right Move focus to header view
1481 * There is no need to scroll to selected row, the widgets will be the
1482 * responsibles of doing that (probably managing the focus-in event
1485 on_inner_widgets_key_pressed (GtkWidget *widget,
1489 ModestMainWindowPrivate *priv;
1491 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1493 /* Do nothing if we're in SIMPLE style */
1494 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1497 if (MODEST_IS_HEADER_VIEW (widget)) {
1498 if (event->keyval == GDK_Left)
1499 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1500 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1501 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1502 if (selected_headers > 1) {
1503 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1507 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1508 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1514 set_alignment (GtkWidget *widget,
1517 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1518 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1522 create_empty_view (void)
1524 GtkLabel *label = NULL;
1525 GtkWidget *align = NULL;
1527 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1528 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1529 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1530 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1532 return GTK_WIDGET(align);
1536 * Free the returned string
1539 get_gray_color_markup (GtkWidget *styled_widget)
1541 gchar *gray_color_markup = NULL;
1542 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1543 /* Obtain the secondary text color. We need a realized widget, that's why
1544 we get styled_widget from outside */
1546 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1547 gray_color_markup = modest_text_utils_get_color_string (&color);
1548 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1550 if (!gray_color_markup)
1551 gray_color_markup = g_strdup ("#BBBBBB");
1553 return gray_color_markup;
1557 * Free the returned string
1560 create_device_name_visual_string (const gchar *device_name,
1561 const gchar *gray_color_markup)
1565 /* We have to use "" to fill the %s of the translation. We can
1566 not just use the device name because the device name is
1567 shown in a different color, so it could not be included
1568 into the <span> tag */
1569 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1570 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1580 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1582 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1587 gchar *gray_color_markup;
1589 vbox = gtk_vbox_new (FALSE, 0);
1591 gray_color_markup = get_gray_color_markup (styled_widget);
1593 /* Account description: */
1594 if (modest_tny_account_is_virtual_local_folders (account)
1595 || (modest_tny_account_is_memory_card_account (account))) {
1597 /* Get device name */
1598 gchar *device_name = NULL;
1599 if (modest_tny_account_is_virtual_local_folders (account))
1600 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1601 MODEST_CONF_DEVICE_NAME, NULL);
1603 device_name = g_strdup (tny_account_get_name (account));
1605 label = create_device_name_visual_string ((const gchar *) device_name,
1606 (const gchar *) gray_color_markup);
1607 label_w = gtk_label_new (NULL);
1608 gtk_label_set_markup (GTK_LABEL (label_w), label);
1609 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1610 g_free (device_name);
1613 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1614 gtk_box_pack_start (GTK_BOX (vbox),
1615 gtk_label_new (tny_account_get_name (account)),
1618 /* Other accounts, such as IMAP and POP: */
1623 /* Put proto in uppercase */
1624 proto = g_string_new (tny_account_get_proto (account));
1625 proto = g_string_ascii_up (proto);
1627 /* note: mcen_fi_localroot_description is something like "%s account"
1628 * however, we should display "%s account: %s"... therefore, ugly tmp */
1629 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1630 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1631 gray_color_markup, tmp, tny_account_get_name (account));
1634 label_w = gtk_label_new (NULL);
1635 gtk_label_set_markup (GTK_LABEL (label_w), label);
1636 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1637 g_string_free (proto, TRUE);
1643 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1644 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1645 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1646 modest_tny_folder_store_get_message_count (folder_store));
1647 label_w = gtk_label_new (NULL);
1648 gtk_label_set_markup (GTK_LABEL (label_w), label);
1649 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1653 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1655 _("mcen_fi_rootfolder_folders"),
1656 modest_tny_folder_store_get_folder_count (folder_store));
1657 label_w = gtk_label_new (NULL);
1658 gtk_label_set_markup (GTK_LABEL (label_w), label);
1659 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1663 if (modest_tny_account_is_virtual_local_folders (account)
1664 || modest_tny_account_is_memory_card_account (account)) {
1666 gchar *size = modest_text_utils_get_display_size (
1667 modest_tny_folder_store_get_local_size (folder_store));
1669 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1670 gray_color_markup, _("mcen_fi_rootfolder_size"),
1674 label_w = gtk_label_new (NULL);
1675 gtk_label_set_markup (GTK_LABEL (label_w), label);
1676 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1678 } else if (TNY_IS_ACCOUNT(folder_store)) {
1679 TnyAccount *account = TNY_ACCOUNT(folder_store);
1681 time_t last_updated;
1682 const gchar *last_updated_string;
1683 /* Get last updated from configuration */
1684 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1685 tny_account_get_id (account));
1687 if (last_updated > 0)
1688 last_updated_string = modest_text_utils_get_display_date(last_updated);
1690 last_updated_string = g_strdup (_("mcen_va_never"));
1692 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1693 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1694 label_w = gtk_label_new (NULL);
1695 gtk_label_set_markup (GTK_LABEL (label_w), label);
1696 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1700 g_free (gray_color_markup);
1703 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1709 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1711 ModestMainWindowPrivate *priv = NULL;
1713 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1715 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1717 return priv->send_receive_in_progress;
1721 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1723 GtkAction *action = NULL;
1724 GtkWidget *widget = NULL;
1725 ModestMainWindowPrivate *priv = NULL;
1727 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1728 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1730 priv->send_receive_in_progress = TRUE;
1732 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1733 gtk_action_set_sensitive (action, FALSE);
1734 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1735 /* gtk_action_set_sensitive (action, FALSE); */
1736 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1737 gtk_widget_set_sensitive (widget, FALSE);
1741 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1743 GtkAction *action = NULL;
1744 GtkWidget *widget = NULL;
1745 ModestMainWindowPrivate *priv = NULL;
1747 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1748 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1750 priv->send_receive_in_progress = FALSE;
1752 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1753 gtk_action_set_sensitive (action, TRUE);
1754 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1755 /* gtk_action_set_sensitive (action, TRUE); */
1756 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1757 gtk_widget_set_sensitive (widget, TRUE);
1762 on_msg_count_changed (ModestHeaderView *header_view,
1764 TnyFolderChange *change,
1765 ModestMainWindow *main_window)
1767 gboolean folder_empty = FALSE;
1768 gboolean all_marked_as_deleted = FALSE;
1769 TnyFolderChangeChanged changed;
1770 ModestMainWindowPrivate *priv;
1772 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1773 g_return_if_fail (TNY_IS_FOLDER(folder));
1774 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1775 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1777 changed = tny_folder_change_get_changed (change);
1779 /* If something changes */
1780 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1781 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1783 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1785 /* Check header removed (hide marked as DELETED headers) */
1786 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1787 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1790 /* Check if all messages are marked to be deleted */
1791 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1792 folder_empty = folder_empty || all_marked_as_deleted ;
1794 /* Set contents style of headers view */
1796 modest_main_window_set_contents_style (main_window,
1797 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1798 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1801 modest_main_window_set_contents_style (main_window,
1802 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1808 modest_main_window_set_contents_style (ModestMainWindow *self,
1809 ModestMainWindowContentsStyle style)
1811 ModestMainWindowPrivate *priv;
1813 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1815 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1817 /* We allow to set the same content style than the previously
1818 set if there are details, because it could happen when we're
1819 selecting different accounts consecutively */
1820 if ((priv->contents_style == style) &&
1821 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1824 /* Remove previous child. Delete it if it was an account
1826 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1828 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1829 g_object_ref (content);
1830 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1831 g_object_ref (priv->empty_view);
1832 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1835 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1838 priv->contents_style = style;
1840 switch (priv->contents_style) {
1841 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1842 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1843 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1846 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1848 /* if we're started without main win, there may not be a folder
1849 * view. this fixes a GLib-Critical */
1850 if (priv->folder_view) {
1851 TnyFolderStore *selected_folderstore =
1852 modest_folder_view_get_selected (priv->folder_view);
1853 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1854 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1855 TNY_ACCOUNT (selected_folderstore));
1857 wrap_in_scrolled_window (priv->contents_widget,
1858 priv->details_widget);
1860 g_object_unref (selected_folderstore);
1861 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1866 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1867 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1868 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1872 g_return_if_reached ();
1876 gtk_widget_show_all (priv->contents_widget);
1879 ModestMainWindowContentsStyle
1880 modest_main_window_get_contents_style (ModestMainWindow *self)
1882 ModestMainWindowPrivate *priv;
1884 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1886 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1887 return priv->contents_style;
1892 on_configuration_key_changed (ModestConf* conf,
1894 ModestConfEvent event,
1895 ModestConfNotificationId id,
1896 ModestMainWindow *self)
1898 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1899 TnyAccount *account = NULL;
1901 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1904 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1907 if (priv->folder_view)
1908 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1910 if (account && TNY_IS_ACCOUNT (account) &&
1911 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1914 const gchar *device_name;
1915 gchar *new_text, *gray_color_markup;
1918 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1919 label = GTK_LABEL (children->data);
1921 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1922 MODEST_CONF_DEVICE_NAME, NULL);
1924 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1925 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1927 gtk_label_set_markup (label, new_text);
1928 gtk_widget_show (GTK_WIDGET (label));
1930 g_free (gray_color_markup);
1932 g_list_free (children);
1934 g_object_unref (account);
1938 set_toolbar_transfer_mode (ModestMainWindow *self)
1940 ModestMainWindowPrivate *priv = NULL;
1942 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1944 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1946 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1948 if (priv->progress_bar_timeout > 0) {
1949 g_source_remove (priv->progress_bar_timeout);
1950 priv->progress_bar_timeout = 0;
1957 set_toolbar_mode (ModestMainWindow *self,
1958 ModestToolBarModes mode)
1960 ModestWindowPrivate *parent_priv = NULL;
1961 ModestMainWindowPrivate *priv = NULL;
1962 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1964 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1966 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1967 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1969 /* In case this was called before the toolbar exists: */
1970 if (!(parent_priv->toolbar))
1973 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1975 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1976 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1977 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1979 /* Sets current toolbar mode */
1980 priv->current_toolbar_mode = mode;
1982 /* Checks the dimming rules */
1983 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1985 /* Show and hide toolbar items */
1987 case TOOLBAR_MODE_NORMAL:
1989 gtk_action_set_visible (sort_action, TRUE);
1991 gtk_action_set_visible (refresh_action, TRUE);
1992 if (priv->progress_toolitem) {
1993 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1994 gtk_widget_hide (priv->progress_toolitem);
1996 if (priv->progress_bar)
1997 gtk_widget_hide (priv->progress_bar);
2000 gtk_action_set_visible (cancel_action, FALSE);
2002 /* Hide toolbar if optimized view is enabled */
2003 if (priv->optimized_view)
2004 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2006 case TOOLBAR_MODE_TRANSFER:
2008 gtk_action_set_visible (sort_action, FALSE);
2010 gtk_action_set_visible (refresh_action, FALSE);
2012 gtk_action_set_visible (cancel_action, TRUE);
2013 if (priv->progress_toolitem) {
2014 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2015 gtk_widget_show (priv->progress_toolitem);
2017 if (priv->progress_bar)
2018 gtk_widget_show (priv->progress_bar);
2020 /* Show toolbar if it's hiden (optimized view ) */
2021 if (priv->optimized_view)
2022 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2025 g_return_if_reached ();
2030 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2032 ModestMainWindowPrivate *priv;
2034 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2035 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2037 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2041 cancel_progressbar (GtkToolButton *toolbutton,
2042 ModestMainWindow *self)
2045 ModestMainWindowPrivate *priv;
2047 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2049 /* Get operation observers and cancel all the operations */
2050 tmp = priv->progress_widgets;
2052 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2053 tmp=g_slist_next(tmp);
2058 observers_empty (ModestMainWindow *self)
2061 ModestMainWindowPrivate *priv;
2062 gboolean is_empty = TRUE;
2063 guint pending_ops = 0;
2065 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2066 tmp = priv->progress_widgets;
2068 /* Check all observers */
2069 while (tmp && is_empty) {
2070 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2071 is_empty = pending_ops == 0;
2073 tmp = g_slist_next(tmp);
2081 * Gets the toolbar mode needed for each mail operation. It stores in
2082 * @mode_changed if the toolbar mode has changed or not
2084 static ModestToolBarModes
2085 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2086 ModestMailOperation *mail_op,
2087 gboolean *mode_changed)
2089 ModestToolBarModes mode;
2090 ModestMainWindowPrivate *priv;
2092 *mode_changed = FALSE;
2093 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2095 /* Get toolbar mode from operation id*/
2096 switch (modest_mail_operation_get_type_operation (mail_op)) {
2097 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2098 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2099 mode = TOOLBAR_MODE_TRANSFER;
2100 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2101 *mode_changed = TRUE;
2104 mode = TOOLBAR_MODE_NORMAL;
2110 on_mail_operation_started (ModestMailOperation *mail_op,
2113 ModestMainWindow *self;
2114 ModestMailOperationTypeOperation op_type;
2115 ModestMainWindowPrivate *priv;
2116 ModestToolBarModes mode;
2118 gboolean mode_changed = FALSE;
2119 TnyAccount *account;
2121 self = MODEST_MAIN_WINDOW (user_data);
2122 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2124 /* Do not show progress for receiving operations if the
2125 account is the local account or the MMC one */
2126 op_type = modest_mail_operation_get_type_operation (mail_op);
2127 account = modest_mail_operation_get_account (mail_op);
2128 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2131 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2132 modest_tny_account_is_memory_card_account (account));
2133 g_object_unref (account);
2138 /* Get toolbar mode from operation id*/
2139 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2141 /* Add operation observers and change toolbar if neccessary*/
2142 tmp = priv->progress_widgets;
2143 if (mode == TOOLBAR_MODE_TRANSFER) {
2145 set_toolbar_transfer_mode(self);
2148 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2150 tmp = g_slist_next (tmp);
2156 on_mail_operation_finished (ModestMailOperation *mail_op,
2159 ModestToolBarModes mode;
2160 ModestMailOperationTypeOperation op_type;
2162 ModestMainWindow *self;
2163 gboolean mode_changed;
2164 TnyAccount *account;
2165 ModestMainWindowPrivate *priv;
2167 self = MODEST_MAIN_WINDOW (user_data);
2168 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2170 /* The mail operation was not added to the progress objects if
2171 the account was the local account or the MMC one */
2172 op_type = modest_mail_operation_get_type_operation (mail_op);
2173 account = modest_mail_operation_get_account (mail_op);
2174 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2177 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2178 modest_tny_account_is_memory_card_account (account));
2179 g_object_unref (account);
2184 /* Get toolbar mode from operation id*/
2185 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2187 /* Change toolbar mode */
2188 tmp = priv->progress_widgets;
2189 if (mode == TOOLBAR_MODE_TRANSFER) {
2191 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2193 tmp = g_slist_next (tmp);
2196 /* If no more operations are being observed, NORMAL mode is enabled again */
2197 if (observers_empty (self)) {
2198 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2204 on_queue_changed (ModestMailOperationQueue *queue,
2205 ModestMailOperation *mail_op,
2206 ModestMailOperationQueueNotification type,
2207 ModestMainWindow *self)
2209 ModestMainWindowPrivate *priv;
2211 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2213 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2214 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2216 "operation-started",
2217 G_CALLBACK (on_mail_operation_started),
2219 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2221 "operation-finished",
2222 G_CALLBACK (on_mail_operation_finished),
2224 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2225 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2227 "operation-started");
2228 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2230 "operation-finished");
2235 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2237 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2240 /* Get account data */
2241 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2242 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2244 /* Set the new visible & active account */
2245 if (acc_data && acc_data->store_account) {
2246 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2247 acc_data->store_account->account_name);
2248 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2249 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2250 if (action != NULL) {
2251 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2252 modest_maemo_toggle_action_set_active_block_notify (
2253 GTK_TOGGLE_ACTION (action),
2259 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2264 modest_account_mgr_free_account_data (mgr, acc_data);
2267 /* Make sure that at least one account is "viewed": */
2269 set_at_least_one_account_visible(ModestMainWindow *self)
2271 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2272 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2274 if (!(priv->folder_view)) {
2275 /* It is too early to do this. */
2279 const gchar *active_server_account_name =
2280 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2282 if (!active_server_account_name ||
2283 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2285 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2286 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2287 if (default_modest_name) {
2288 set_account_visible (self, default_modest_name);
2289 } else if (first_modest_name) {
2290 set_account_visible (self, first_modest_name);
2292 g_free (first_modest_name);
2293 g_free (default_modest_name);
2298 on_show_account_action_toggled (GtkToggleAction *action,
2301 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2303 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2304 if (gtk_toggle_action_get_active (action))
2305 set_account_visible (self, acc_name);
2309 refresh_account (const gchar *account_name)
2313 /* win must already exists here, obviously */
2314 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2317 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2321 /* If account_name == NULL, we must update all (option All) */
2323 modest_ui_actions_do_send_receive_all (win);
2325 modest_ui_actions_do_send_receive (account_name, win);
2330 on_refresh_account_action_activated (GtkAction *action,
2333 refresh_account ((const gchar*) user_data);
2337 on_send_receive_csm_activated (GtkMenuItem *item,
2340 refresh_account ((const gchar*) user_data);
2344 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2346 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2348 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2354 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2356 ModestMainWindow *main_window = NULL;
2358 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2359 main_window = MODEST_MAIN_WINDOW (userdata);
2361 /* Update toolbar dimming state */
2362 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2368 on_header_view_focus_in (GtkWidget *widget,
2369 GdkEventFocus *event,
2372 ModestMainWindow *main_window = NULL;
2374 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2376 main_window = MODEST_MAIN_WINDOW (userdata);
2378 /* Update toolbar dimming state */
2379 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2385 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2386 TnyFolderStore *folder_store,
2388 ModestMainWindow *main_window)
2390 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2391 GtkAction *action = NULL;
2392 gboolean show_reply = TRUE;
2393 gboolean show_forward = TRUE;
2394 gboolean show_cancel_send = FALSE;
2395 gboolean show_clipboard = TRUE;
2396 gboolean show_delete = TRUE;
2399 if (TNY_IS_ACCOUNT (folder_store)) {
2400 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2401 } else if (TNY_IS_FOLDER (folder_store)) {
2402 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2403 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2404 TNY_FOLDER (folder_store));
2405 switch (folder_type) {
2406 case TNY_FOLDER_TYPE_DRAFTS:
2407 show_clipboard = show_delete = TRUE;
2408 show_reply = show_forward = show_cancel_send = FALSE;
2410 case TNY_FOLDER_TYPE_SENT:
2411 show_forward = show_clipboard = show_delete = TRUE;
2412 show_reply = show_cancel_send = FALSE;
2414 case TNY_FOLDER_TYPE_OUTBOX:
2415 show_clipboard = show_delete = show_cancel_send = TRUE;
2416 show_reply = show_forward = FALSE;
2418 case TNY_FOLDER_TYPE_INVALID:
2419 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2422 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2423 show_cancel_send = FALSE;
2426 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2427 show_cancel_send = FALSE;
2432 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2433 gtk_action_set_visible (action, show_reply);
2434 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2435 gtk_action_set_visible (action, show_reply);
2436 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2437 gtk_action_set_visible (action, show_forward);
2438 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2439 gtk_action_set_visible (action, show_cancel_send);
2440 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2441 gtk_action_set_visible (action, show_delete);
2443 /* We finally call to the ui actions handler, after updating properly
2444 * the header view CSM */
2445 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2449 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2450 GtkTreeModel *model,
2451 GtkTreeRowReference *row_reference,
2452 ModestMainWindow *self)
2454 ModestMainWindowPrivate *priv = NULL;
2455 GtkTreeModel *header_model = NULL;
2456 GtkTreePath *path = NULL;
2458 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2459 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2460 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2462 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2463 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2465 /* Do nothing if we changed the folder in the main view */
2466 if (header_model != model)
2469 /* Select the message in the header view */
2470 path = gtk_tree_row_reference_get_path (row_reference);
2471 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2473 gtk_tree_path_free (path);
2479 show_updating_banner (gpointer user_data)
2481 ModestMainWindowPrivate *priv = NULL;
2483 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2485 if (priv->updating_banner == NULL) {
2487 /* We're outside the main lock */
2488 gdk_threads_enter ();
2489 priv->updating_banner =
2490 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2491 _CS ("ckdg_pb_updating"));
2492 gdk_threads_leave ();
2495 /* Remove timeout */
2496 priv->updating_banner_timeout = 0;
2501 * We use this function to show/hide a progress banner showing
2502 * "Updating" while the header view is being filled. We're not showing
2503 * it unless the update takes more than 2 seconds
2505 * If starting = TRUE then the refresh is starting, otherwise it means
2506 * that is has just finished
2509 on_updating_msg_list (ModestHeaderView *header_view,
2513 ModestMainWindowPrivate *priv = NULL;
2515 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2517 /* Remove old timeout */
2518 if (priv->updating_banner_timeout > 0) {
2519 g_source_remove (priv->updating_banner_timeout);
2520 priv->updating_banner_timeout = 0;
2523 /* Create a new timeout */
2525 priv->updating_banner_timeout =
2526 g_timeout_add (2000, show_updating_banner, user_data);
2528 /* Remove the banner if exists */
2529 if (priv->updating_banner) {
2530 gtk_widget_destroy (priv->updating_banner);
2531 priv->updating_banner = NULL;