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));
1030 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
1032 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1034 /* Connect signals */
1035 connect_signals (MODEST_MAIN_WINDOW (self));
1037 /* Set account store */
1038 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1039 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1041 /* Load previous osso state, for instance if we are being restored from
1043 modest_osso_load_state ();
1045 /* Restore window & widget settings */
1046 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1048 /* /\* The UI spec wants us to show a connection dialog when the application is */
1049 /* * started by the user, if there is no connection. */
1050 /* * Do this before showing the account wizard, */
1051 /* * because wizard needs a connection to discover capabilities. *\/ */
1052 /* modest_platform_connect_and_wait (GTK_WINDOW (self), NULL); */
1054 /* Check if accounts exist and show the account wizard if not */
1055 gboolean accounts_exist =
1056 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1058 if (!accounts_exist) {
1059 /* This is necessary to have the main window shown behind the dialog
1060 It's an ugly hack... jschmid */
1061 gtk_widget_show_all(GTK_WIDGET(self));
1062 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1065 GtkAction *send_receive_all;
1066 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1067 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1068 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1069 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1070 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1071 modest_account_mgr_free_account_names (accounts);
1072 update_menus (MODEST_MAIN_WINDOW (self));
1077 modest_main_window_new (void)
1079 ModestMainWindow *self = NULL;
1080 ModestMainWindowPrivate *priv = NULL;
1081 ModestWindowPrivate *parent_priv = NULL;
1082 GtkWidget *folder_win = NULL;
1083 ModestDimmingRulesGroup *menu_rules_group = NULL;
1084 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1085 GtkActionGroup *action_group = NULL;
1086 GError *error = NULL;
1087 ModestConf *conf = NULL;
1088 GtkAction *action = NULL;
1089 GdkPixbuf *window_icon;
1091 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1092 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1093 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1095 parent_priv->ui_manager = gtk_ui_manager_new();
1096 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1098 action_group = gtk_action_group_new ("ModestMainWindowActions");
1099 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1101 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1102 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1104 /* Add common actions */
1105 gtk_action_group_add_actions (action_group,
1106 modest_action_entries,
1107 G_N_ELEMENTS (modest_action_entries),
1110 gtk_action_group_add_actions (action_group,
1111 modest_folder_view_action_entries,
1112 G_N_ELEMENTS (modest_folder_view_action_entries),
1115 gtk_action_group_add_actions (action_group,
1116 modest_header_view_action_entries,
1117 G_N_ELEMENTS (modest_header_view_action_entries),
1120 gtk_action_group_add_toggle_actions (action_group,
1121 modest_toggle_action_entries,
1122 G_N_ELEMENTS (modest_toggle_action_entries),
1125 gtk_action_group_add_toggle_actions (action_group,
1126 modest_main_window_toggle_action_entries,
1127 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1130 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1131 g_object_unref (action_group);
1133 /* Load the UI definition */
1134 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1135 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1136 if (error != NULL) {
1137 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1138 g_error_free (error);
1142 /* Add common dimming rules */
1143 modest_dimming_rules_group_add_rules (menu_rules_group,
1144 modest_main_window_menu_dimming_entries,
1145 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1146 MODEST_WINDOW (self));
1147 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1148 modest_main_window_toolbar_dimming_entries,
1149 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1150 MODEST_WINDOW (self));
1152 /* Insert dimming rules group for this window */
1153 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1154 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1155 g_object_unref (menu_rules_group);
1156 g_object_unref (toolbar_rules_group);
1158 /* Add accelerators */
1159 gtk_window_add_accel_group (GTK_WINDOW (self),
1160 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1162 /* Menubar. Update the state of some toggles */
1163 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1164 conf = modest_runtime_get_conf ();
1165 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1166 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1167 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1168 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1169 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1170 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1171 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1172 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1173 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1174 gtk_widget_show (parent_priv->menubar);
1176 /* Get device name */
1177 modest_maemo_utils_get_device_name ();
1181 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1182 if (!priv->header_view)
1183 g_printerr ("modest: cannot instantiate header view\n");
1184 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1185 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1186 MODEST_CONF_HEADER_VIEW_KEY);
1188 /* Other style properties of header view */
1189 g_object_set (G_OBJECT (priv->header_view),
1190 "rules-hint", FALSE,
1192 /* gtk_widget_show (priv->header_view); */
1195 priv->empty_view = create_empty_view ();
1196 gtk_widget_show (priv->empty_view);
1198 /* Create scrolled windows */
1199 folder_win = gtk_scrolled_window_new (NULL, NULL);
1200 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1201 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1203 GTK_POLICY_AUTOMATIC);
1204 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1206 GTK_POLICY_AUTOMATIC);
1207 /* gtk_widget_show (priv->contents_widget); */
1210 priv->main_paned = gtk_hpaned_new ();
1211 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1212 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1213 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1215 /* putting it all together... */
1216 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1217 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1218 gtk_widget_show (priv->main_vbox);
1220 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1222 HildonProgram *app = hildon_program_get_instance ();
1223 hildon_program_add_window (app, HILDON_WINDOW (self));
1225 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1226 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1228 g_signal_connect (G_OBJECT(self), "show",
1229 G_CALLBACK (modest_main_window_on_show), folder_win);
1231 /* Set window icon */
1232 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1234 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1235 g_object_unref (window_icon);
1238 /* Dont't restore settings here,
1239 * because it requires a gtk_widget_show(),
1240 * and we don't want to do that until later,
1241 * so that the UI is not visible for non-menu D-Bus activation.
1243 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1245 return MODEST_WINDOW(self);
1249 modest_main_window_set_style (ModestMainWindow *self,
1250 ModestMainWindowStyle style)
1252 ModestMainWindowPrivate *priv;
1253 ModestWindowPrivate *parent_priv;
1257 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1259 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1260 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1262 /* no change -> nothing to do */
1263 if (priv->style == style)
1266 /* Get toggle button and update the state if needed. This will
1267 happen only when the set_style is not invoked from the UI,
1268 for example when it's called from widget memory */
1269 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1270 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1271 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1272 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1273 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1274 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1275 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1278 priv->style = style;
1280 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1281 /* Remove main paned */
1282 g_object_ref (priv->main_paned);
1283 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1285 /* Reparent the contents widget to the main vbox */
1286 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1289 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1290 /* Remove header view */
1291 g_object_ref (priv->contents_widget);
1292 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1294 /* Reparent the main paned */
1295 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1296 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1300 g_return_if_reached ();
1303 /* Let header view grab the focus if it's being shown */
1304 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1305 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1307 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1310 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1313 ModestMainWindowStyle
1314 modest_main_window_get_style (ModestMainWindow *self)
1316 ModestMainWindowPrivate *priv;
1318 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1320 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1327 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1329 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1330 ModestWindowPrivate *parent_priv;
1331 ModestWindowMgr *mgr;
1332 gboolean is_fullscreen;
1333 GtkAction *fs_toggle_action;
1336 mgr = modest_runtime_get_window_mgr ();
1338 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1340 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1342 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1343 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1344 if (is_fullscreen != active) {
1345 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1354 set_homogeneous (GtkWidget *widget,
1357 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1358 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1362 modest_main_window_show_toolbar (ModestWindow *self,
1363 gboolean show_toolbar)
1365 ModestMainWindowPrivate *priv = NULL;
1366 ModestWindowPrivate *parent_priv = NULL;
1367 GtkWidget *reply_button = NULL, *menu = NULL;
1368 GtkWidget *placeholder = NULL;
1370 const gchar *action_name;
1373 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1374 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1375 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1377 /* Set optimized view status */
1378 priv->optimized_view = !show_toolbar;
1380 if (!parent_priv->toolbar) {
1381 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1383 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1385 /* Set homogeneous toolbar */
1386 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1387 set_homogeneous, NULL);
1389 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1390 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1391 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1392 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1393 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1394 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1395 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1396 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1398 /* Add ProgressBar (Transfer toolbar) */
1399 priv->progress_bar = modest_progress_bar_widget_new ();
1400 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1401 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1402 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1403 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1404 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1406 /* Connect cancel 'clicked' signal to abort progress mode */
1407 g_signal_connect(priv->cancel_toolitem, "clicked",
1408 G_CALLBACK(cancel_progressbar),
1411 /* Add it to the observers list */
1412 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1415 hildon_window_add_toolbar (HILDON_WINDOW (self),
1416 GTK_TOOLBAR (parent_priv->toolbar));
1418 /* Set reply button tap and hold menu */
1419 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1420 "/ToolBar/ToolbarMessageReply");
1421 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1422 "/ToolbarReplyCSM");
1423 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1425 /* Set send & receive button tap and hold menu */
1426 update_menus (MODEST_MAIN_WINDOW (self));
1430 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1431 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1432 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1434 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1435 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1437 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1441 /* Update also the actions (to update the toggles in the
1442 menus), we have to do it manually because some other window
1443 of the same time could have changed it (remember that the
1444 toolbar fullscreen mode is shared by all the windows of the
1446 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1447 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1449 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1451 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1452 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1457 on_account_inserted (TnyAccountStore *accoust_store,
1458 TnyAccount *account,
1461 update_menus (MODEST_MAIN_WINDOW (user_data));
1465 on_default_account_changed (ModestAccountMgr* mgr,
1468 update_menus (MODEST_MAIN_WINDOW (user_data));
1472 on_account_removed (TnyAccountStore *accoust_store,
1473 TnyAccount *account,
1476 update_menus (MODEST_MAIN_WINDOW (user_data));
1480 * This function manages the key events used to navigate between
1481 * header and folder views (when the window is in split view)
1484 * -------------------------------------------------
1485 * HeaderView GDK_Left Move focus to folder view
1486 * FolderView GDK_Right Move focus to header view
1488 * There is no need to scroll to selected row, the widgets will be the
1489 * responsibles of doing that (probably managing the focus-in event
1492 on_inner_widgets_key_pressed (GtkWidget *widget,
1496 ModestMainWindowPrivate *priv;
1498 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1500 /* Do nothing if we're in SIMPLE style */
1501 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1504 if (MODEST_IS_HEADER_VIEW (widget)) {
1505 if (event->keyval == GDK_Left)
1506 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1507 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1508 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1509 if (selected_headers > 1) {
1510 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1514 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1515 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1521 set_alignment (GtkWidget *widget,
1524 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1525 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1529 create_empty_view (void)
1531 GtkLabel *label = NULL;
1532 GtkWidget *align = NULL;
1534 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1535 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1536 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1537 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1539 return GTK_WIDGET(align);
1543 * Free the returned string
1546 get_gray_color_markup (GtkWidget *styled_widget)
1548 gchar *gray_color_markup = NULL;
1549 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1550 /* Obtain the secondary text color. We need a realized widget, that's why
1551 we get styled_widget from outside */
1553 if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color))
1554 gray_color_markup = modest_text_utils_get_color_string (&color);
1555 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1557 if (!gray_color_markup)
1558 gray_color_markup = g_strdup ("#BBBBBB");
1560 return gray_color_markup;
1564 * Free the returned string
1567 create_device_name_visual_string (const gchar *device_name,
1568 const gchar *gray_color_markup)
1572 /* We have to use "" to fill the %s of the translation. We can
1573 not just use the device name because the device name is
1574 shown in a different color, so it could not be included
1575 into the <span> tag */
1576 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1577 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1587 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1589 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1594 gchar *gray_color_markup;
1596 vbox = gtk_vbox_new (FALSE, 0);
1598 gray_color_markup = get_gray_color_markup (styled_widget);
1600 /* Account description: */
1601 if (modest_tny_account_is_virtual_local_folders (account)
1602 || (modest_tny_account_is_memory_card_account (account))) {
1604 /* Get device name */
1605 gchar *device_name = NULL;
1606 if (modest_tny_account_is_virtual_local_folders (account))
1607 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1608 MODEST_CONF_DEVICE_NAME, NULL);
1610 device_name = g_strdup (tny_account_get_name (account));
1612 label = create_device_name_visual_string ((const gchar *) device_name,
1613 (const gchar *) gray_color_markup);
1614 label_w = gtk_label_new (NULL);
1615 gtk_label_set_markup (GTK_LABEL (label_w), label);
1616 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1617 g_free (device_name);
1620 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1621 gtk_box_pack_start (GTK_BOX (vbox),
1622 gtk_label_new (tny_account_get_name (account)),
1625 /* Other accounts, such as IMAP and POP: */
1630 /* Put proto in uppercase */
1631 proto = g_string_new (tny_account_get_proto (account));
1632 proto = g_string_ascii_up (proto);
1634 /* note: mcen_fi_localroot_description is something like "%s account"
1635 * however, we should display "%s account: %s"... therefore, ugly tmp */
1636 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1637 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1638 gray_color_markup, tmp, tny_account_get_name (account));
1641 label_w = gtk_label_new (NULL);
1642 gtk_label_set_markup (GTK_LABEL (label_w), label);
1643 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1644 g_string_free (proto, TRUE);
1650 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1651 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1652 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1653 modest_tny_folder_store_get_message_count (folder_store));
1654 label_w = gtk_label_new (NULL);
1655 gtk_label_set_markup (GTK_LABEL (label_w), label);
1656 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1660 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1662 _("mcen_fi_rootfolder_folders"),
1663 modest_tny_folder_store_get_folder_count (folder_store));
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);
1670 if (modest_tny_account_is_virtual_local_folders (account)
1671 || modest_tny_account_is_memory_card_account (account)) {
1673 gchar *size = modest_text_utils_get_display_size (
1674 modest_tny_folder_store_get_local_size (folder_store));
1676 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1677 gray_color_markup, _("mcen_fi_rootfolder_size"),
1681 label_w = gtk_label_new (NULL);
1682 gtk_label_set_markup (GTK_LABEL (label_w), label);
1683 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1685 } else if (TNY_IS_ACCOUNT(folder_store)) {
1686 TnyAccount *account = TNY_ACCOUNT(folder_store);
1688 time_t last_updated;
1689 const gchar *last_updated_string;
1690 /* Get last updated from configuration */
1691 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1692 tny_account_get_id (account));
1694 if (last_updated > 0)
1695 last_updated_string = modest_text_utils_get_display_date(last_updated);
1697 last_updated_string = g_strdup (_("mcen_va_never"));
1699 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1700 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1701 label_w = gtk_label_new (NULL);
1702 gtk_label_set_markup (GTK_LABEL (label_w), label);
1703 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1707 g_free (gray_color_markup);
1710 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1716 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1718 ModestMainWindowPrivate *priv = NULL;
1720 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1722 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1724 return priv->send_receive_in_progress;
1728 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1730 GtkAction *action = NULL;
1731 GtkWidget *widget = NULL;
1732 ModestMainWindowPrivate *priv = NULL;
1734 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1735 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1737 priv->send_receive_in_progress = TRUE;
1739 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1740 gtk_action_set_sensitive (action, FALSE);
1741 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1742 /* gtk_action_set_sensitive (action, FALSE); */
1743 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1744 gtk_widget_set_sensitive (widget, FALSE);
1748 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1750 GtkAction *action = NULL;
1751 GtkWidget *widget = NULL;
1752 ModestMainWindowPrivate *priv = NULL;
1754 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1755 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1757 priv->send_receive_in_progress = FALSE;
1759 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1760 gtk_action_set_sensitive (action, TRUE);
1761 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1762 /* gtk_action_set_sensitive (action, TRUE); */
1763 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1764 gtk_widget_set_sensitive (widget, TRUE);
1769 on_msg_count_changed (ModestHeaderView *header_view,
1771 TnyFolderChange *change,
1772 ModestMainWindow *main_window)
1774 gboolean folder_empty = FALSE;
1775 gboolean all_marked_as_deleted = FALSE;
1776 TnyFolderChangeChanged changed;
1777 ModestMainWindowPrivate *priv;
1779 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1780 g_return_if_fail (TNY_IS_FOLDER(folder));
1781 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1782 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1784 changed = tny_folder_change_get_changed (change);
1786 /* If something changes */
1787 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1788 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1790 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1792 /* Check header removed (hide marked as DELETED headers) */
1793 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1794 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1797 /* Check if all messages are marked to be deleted */
1798 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1799 folder_empty = folder_empty || all_marked_as_deleted ;
1801 /* Set contents style of headers view */
1803 modest_main_window_set_contents_style (main_window,
1804 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1805 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1808 modest_main_window_set_contents_style (main_window,
1809 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1815 modest_main_window_set_contents_style (ModestMainWindow *self,
1816 ModestMainWindowContentsStyle style)
1818 ModestMainWindowPrivate *priv;
1820 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1822 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1824 /* We allow to set the same content style than the previously
1825 set if there are details, because it could happen when we're
1826 selecting different accounts consecutively */
1827 if ((priv->contents_style == style) &&
1828 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1831 /* Remove previous child. Delete it if it was an account
1833 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1835 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1836 g_object_ref (content);
1837 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1838 g_object_ref (priv->empty_view);
1839 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1842 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1845 priv->contents_style = style;
1847 switch (priv->contents_style) {
1848 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1849 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1850 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1853 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1855 /* if we're started without main win, there may not be a folder
1856 * view. this fixes a GLib-Critical */
1857 if (priv->folder_view) {
1858 TnyFolderStore *selected_folderstore =
1859 modest_folder_view_get_selected (priv->folder_view);
1860 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1861 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1862 TNY_ACCOUNT (selected_folderstore));
1864 wrap_in_scrolled_window (priv->contents_widget,
1865 priv->details_widget);
1867 g_object_unref (selected_folderstore);
1868 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1873 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1874 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1875 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1879 g_return_if_reached ();
1883 gtk_widget_show_all (priv->contents_widget);
1886 ModestMainWindowContentsStyle
1887 modest_main_window_get_contents_style (ModestMainWindow *self)
1889 ModestMainWindowPrivate *priv;
1891 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1893 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1894 return priv->contents_style;
1899 on_configuration_key_changed (ModestConf* conf,
1901 ModestConfEvent event,
1902 ModestConfNotificationId id,
1903 ModestMainWindow *self)
1905 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1906 TnyAccount *account = NULL;
1908 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1911 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1914 if (priv->folder_view)
1915 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1917 if (account && TNY_IS_ACCOUNT (account) &&
1918 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1921 const gchar *device_name;
1922 gchar *new_text, *gray_color_markup;
1925 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1926 label = GTK_LABEL (children->data);
1928 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1929 MODEST_CONF_DEVICE_NAME, NULL);
1931 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1932 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1934 gtk_label_set_markup (label, new_text);
1935 gtk_widget_show (GTK_WIDGET (label));
1937 g_free (gray_color_markup);
1939 g_list_free (children);
1941 g_object_unref (account);
1945 set_toolbar_transfer_mode (ModestMainWindow *self)
1947 ModestMainWindowPrivate *priv = NULL;
1949 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1951 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1953 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1955 if (priv->progress_bar_timeout > 0) {
1956 g_source_remove (priv->progress_bar_timeout);
1957 priv->progress_bar_timeout = 0;
1964 set_toolbar_mode (ModestMainWindow *self,
1965 ModestToolBarModes mode)
1967 ModestWindowPrivate *parent_priv = NULL;
1968 ModestMainWindowPrivate *priv = NULL;
1969 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1971 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1973 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1974 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1976 /* In case this was called before the toolbar exists: */
1977 if (!(parent_priv->toolbar))
1980 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1982 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1983 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1984 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1986 /* Sets current toolbar mode */
1987 priv->current_toolbar_mode = mode;
1989 /* Checks the dimming rules */
1990 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1992 /* Show and hide toolbar items */
1994 case TOOLBAR_MODE_NORMAL:
1996 gtk_action_set_visible (sort_action, TRUE);
1998 gtk_action_set_visible (refresh_action, TRUE);
1999 if (priv->progress_toolitem) {
2000 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2001 gtk_widget_hide (priv->progress_toolitem);
2003 if (priv->progress_bar)
2004 gtk_widget_hide (priv->progress_bar);
2007 gtk_action_set_visible (cancel_action, FALSE);
2009 /* Hide toolbar if optimized view is enabled */
2010 if (priv->optimized_view)
2011 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2013 case TOOLBAR_MODE_TRANSFER:
2015 gtk_action_set_visible (sort_action, FALSE);
2017 gtk_action_set_visible (refresh_action, FALSE);
2019 gtk_action_set_visible (cancel_action, TRUE);
2020 if (priv->progress_toolitem) {
2021 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2022 gtk_widget_show (priv->progress_toolitem);
2024 if (priv->progress_bar)
2025 gtk_widget_show (priv->progress_bar);
2027 /* Show toolbar if it's hiden (optimized view ) */
2028 if (priv->optimized_view)
2029 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2032 g_return_if_reached ();
2037 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2039 ModestMainWindowPrivate *priv;
2041 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2042 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2044 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2048 cancel_progressbar (GtkToolButton *toolbutton,
2049 ModestMainWindow *self)
2052 ModestMainWindowPrivate *priv;
2054 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2056 /* Get operation observers and cancel all the operations */
2057 tmp = priv->progress_widgets;
2059 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2060 tmp=g_slist_next(tmp);
2065 observers_empty (ModestMainWindow *self)
2068 ModestMainWindowPrivate *priv;
2069 gboolean is_empty = TRUE;
2070 guint pending_ops = 0;
2072 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2073 tmp = priv->progress_widgets;
2075 /* Check all observers */
2076 while (tmp && is_empty) {
2077 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2078 is_empty = pending_ops == 0;
2080 tmp = g_slist_next(tmp);
2088 * Gets the toolbar mode needed for each mail operation. It stores in
2089 * @mode_changed if the toolbar mode has changed or not
2091 static ModestToolBarModes
2092 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2093 ModestMailOperation *mail_op,
2094 gboolean *mode_changed)
2096 ModestToolBarModes mode;
2097 ModestMainWindowPrivate *priv;
2099 *mode_changed = FALSE;
2100 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2102 /* Get toolbar mode from operation id*/
2103 switch (modest_mail_operation_get_type_operation (mail_op)) {
2104 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2105 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2106 mode = TOOLBAR_MODE_TRANSFER;
2107 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2108 *mode_changed = TRUE;
2111 mode = TOOLBAR_MODE_NORMAL;
2117 on_mail_operation_started (ModestMailOperation *mail_op,
2120 ModestMainWindow *self;
2121 ModestMailOperationTypeOperation op_type;
2122 ModestMainWindowPrivate *priv;
2123 ModestToolBarModes mode;
2125 gboolean mode_changed = FALSE;
2126 TnyAccount *account;
2128 self = MODEST_MAIN_WINDOW (user_data);
2129 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2131 /* Do not show progress for receiving operations if the
2132 account is the local account or the MMC one */
2133 op_type = modest_mail_operation_get_type_operation (mail_op);
2134 account = modest_mail_operation_get_account (mail_op);
2135 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2138 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2139 modest_tny_account_is_memory_card_account (account));
2140 g_object_unref (account);
2145 /* Get toolbar mode from operation id*/
2146 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2148 /* Add operation observers and change toolbar if neccessary*/
2149 tmp = priv->progress_widgets;
2150 if (mode == TOOLBAR_MODE_TRANSFER) {
2152 set_toolbar_transfer_mode(self);
2155 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2157 tmp = g_slist_next (tmp);
2163 on_mail_operation_finished (ModestMailOperation *mail_op,
2166 ModestToolBarModes mode;
2167 ModestMailOperationTypeOperation op_type;
2169 ModestMainWindow *self;
2170 gboolean mode_changed;
2171 TnyAccount *account;
2172 ModestMainWindowPrivate *priv;
2174 self = MODEST_MAIN_WINDOW (user_data);
2175 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2177 /* The mail operation was not added to the progress objects if
2178 the account was the local account or the MMC one */
2179 op_type = modest_mail_operation_get_type_operation (mail_op);
2180 account = modest_mail_operation_get_account (mail_op);
2181 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2184 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2185 modest_tny_account_is_memory_card_account (account));
2186 g_object_unref (account);
2191 /* Get toolbar mode from operation id*/
2192 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2194 /* Change toolbar mode */
2195 tmp = priv->progress_widgets;
2196 if (mode == TOOLBAR_MODE_TRANSFER) {
2198 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2200 tmp = g_slist_next (tmp);
2203 /* If no more operations are being observed, NORMAL mode is enabled again */
2204 if (observers_empty (self)) {
2205 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2211 on_queue_changed (ModestMailOperationQueue *queue,
2212 ModestMailOperation *mail_op,
2213 ModestMailOperationQueueNotification type,
2214 ModestMainWindow *self)
2216 ModestMainWindowPrivate *priv;
2218 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2220 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2221 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2223 "operation-started",
2224 G_CALLBACK (on_mail_operation_started),
2226 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2228 "operation-finished",
2229 G_CALLBACK (on_mail_operation_finished),
2231 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2232 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2234 "operation-started");
2235 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2237 "operation-finished");
2242 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2244 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2247 /* Get account data */
2248 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2249 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2251 /* Set the new visible & active account */
2252 if (acc_data && acc_data->store_account) {
2253 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2254 acc_data->store_account->account_name);
2255 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2256 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2257 if (action != NULL) {
2258 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2259 modest_maemo_toggle_action_set_active_block_notify (
2260 GTK_TOGGLE_ACTION (action),
2266 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2271 modest_account_mgr_free_account_data (mgr, acc_data);
2274 /* Make sure that at least one account is "viewed": */
2276 set_at_least_one_account_visible(ModestMainWindow *self)
2278 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2279 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2281 if (!(priv->folder_view)) {
2282 /* It is too early to do this. */
2286 const gchar *active_server_account_name =
2287 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2289 if (!active_server_account_name ||
2290 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2292 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2293 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2294 if (default_modest_name) {
2295 set_account_visible (self, default_modest_name);
2296 } else if (first_modest_name) {
2297 set_account_visible (self, first_modest_name);
2299 g_free (first_modest_name);
2300 g_free (default_modest_name);
2305 on_show_account_action_toggled (GtkToggleAction *action,
2308 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2310 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2311 if (gtk_toggle_action_get_active (action))
2312 set_account_visible (self, acc_name);
2316 refresh_account (const gchar *account_name)
2320 /* win must already exists here, obviously */
2321 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2324 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2328 /* If account_name == NULL, we must update all (option All) */
2330 modest_ui_actions_do_send_receive_all (win);
2332 modest_ui_actions_do_send_receive (account_name, win);
2337 on_refresh_account_action_activated (GtkAction *action,
2340 refresh_account ((const gchar*) user_data);
2344 on_send_receive_csm_activated (GtkMenuItem *item,
2347 refresh_account ((const gchar*) user_data);
2351 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2353 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2355 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2361 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2363 ModestMainWindow *main_window = NULL;
2365 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2366 main_window = MODEST_MAIN_WINDOW (userdata);
2368 /* Update toolbar dimming state */
2369 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2375 on_header_view_focus_in (GtkWidget *widget,
2376 GdkEventFocus *event,
2379 ModestMainWindow *main_window = NULL;
2381 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2383 main_window = MODEST_MAIN_WINDOW (userdata);
2385 /* Update toolbar dimming state */
2386 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2392 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2393 TnyFolderStore *folder_store,
2395 ModestMainWindow *main_window)
2397 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2398 GtkAction *action = NULL;
2399 gboolean show_reply = TRUE;
2400 gboolean show_forward = TRUE;
2401 gboolean show_cancel_send = FALSE;
2402 gboolean show_clipboard = TRUE;
2403 gboolean show_delete = TRUE;
2406 if (TNY_IS_ACCOUNT (folder_store)) {
2407 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2408 } else if (TNY_IS_FOLDER (folder_store)) {
2409 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2410 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2411 TNY_FOLDER (folder_store));
2412 switch (folder_type) {
2413 case TNY_FOLDER_TYPE_DRAFTS:
2414 show_clipboard = show_delete = TRUE;
2415 show_reply = show_forward = show_cancel_send = FALSE;
2417 case TNY_FOLDER_TYPE_SENT:
2418 show_forward = show_clipboard = show_delete = TRUE;
2419 show_reply = show_cancel_send = FALSE;
2421 case TNY_FOLDER_TYPE_OUTBOX:
2422 show_clipboard = show_delete = show_cancel_send = TRUE;
2423 show_reply = show_forward = FALSE;
2425 case TNY_FOLDER_TYPE_INVALID:
2426 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2429 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2430 show_cancel_send = FALSE;
2433 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2434 show_cancel_send = FALSE;
2439 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2440 gtk_action_set_visible (action, show_reply);
2441 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2442 gtk_action_set_visible (action, show_reply);
2443 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2444 gtk_action_set_visible (action, show_forward);
2445 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2446 gtk_action_set_visible (action, show_cancel_send);
2447 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2448 gtk_action_set_visible (action, show_delete);
2450 /* We finally call to the ui actions handler, after updating properly
2451 * the header view CSM */
2452 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2456 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2457 GtkTreeModel *model,
2458 GtkTreeRowReference *row_reference,
2459 ModestMainWindow *self)
2461 ModestMainWindowPrivate *priv = NULL;
2462 GtkTreeModel *header_model = NULL;
2463 GtkTreePath *path = NULL;
2465 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2466 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2467 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2469 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2470 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2472 /* Do nothing if we changed the folder in the main view */
2473 if (header_model != model)
2476 /* Select the message in the header view */
2477 path = gtk_tree_row_reference_get_path (row_reference);
2478 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2480 gtk_tree_path_free (path);
2486 show_updating_banner (gpointer user_data)
2488 ModestMainWindowPrivate *priv = NULL;
2490 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2492 if (priv->updating_banner == NULL) {
2494 /* We're outside the main lock */
2495 gdk_threads_enter ();
2496 priv->updating_banner =
2497 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2498 _CS ("ckdg_pb_updating"));
2499 gdk_threads_leave ();
2502 /* Remove timeout */
2503 priv->updating_banner_timeout = 0;
2508 * We use this function to show/hide a progress banner showing
2509 * "Updating" while the header view is being filled. We're not showing
2510 * it unless the update takes more than 2 seconds
2512 * If starting = TRUE then the refresh is starting, otherwise it means
2513 * that is has just finished
2516 on_updating_msg_list (ModestHeaderView *header_view,
2520 ModestMainWindowPrivate *priv = NULL;
2522 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2524 /* Remove old timeout */
2525 if (priv->updating_banner_timeout > 0) {
2526 g_source_remove (priv->updating_banner_timeout);
2527 priv->updating_banner_timeout = 0;
2530 /* Create a new timeout */
2532 priv->updating_banner_timeout =
2533 g_timeout_add (2000, show_updating_banner, user_data);
2535 /* Remove the banner if exists */
2536 if (priv->updating_banner) {
2537 gtk_widget_destroy (priv->updating_banner);
2538 priv->updating_banner = NULL;