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 == NULL)
603 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
606 priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
608 for (i = 0; i < num_accounts; i++) {
609 gchar *display_name = NULL;
610 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
612 if (default_account && account_data->account_name &&
613 !(strcmp (default_account, account_data->account_name) == 0)) {
614 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
615 account_data->display_name);
618 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
619 account_data->display_name);
622 /* Create action and add it to the action group. The
623 action name must be the account name, this way we
624 could know in the handlers the account to show */
625 if(account_data && account_data->account_name) {
626 gchar* item_name, *refresh_action_name;
628 GtkAction *view_account_action, *refresh_account_action;
630 view_account_action = GTK_ACTION (gtk_radio_action_new (account_data->account_name,
631 display_name, NULL, NULL, 0));
632 gtk_action_group_add_action (priv->view_additions_group, view_account_action);
633 gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
634 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
636 if (active_account_name) {
637 if (active_account_name && account_data->account_name &&
638 (strcmp (active_account_name, account_data->account_name) == 0)) {
639 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
643 /* Add ui from account data. We allow 2^9-1 account
644 changes in a single execution because we're
645 downcasting the guint to a guint8 in order to use a
646 GByteArray. It should be enough. */
647 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
648 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
649 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
650 gtk_ui_manager_add_ui (parent_priv->ui_manager,
652 "/MenuBar/ViewMenu/ViewMenuAdditions",
654 account_data->account_name,
655 GTK_UI_MANAGER_MENUITEM,
658 /* Connect the action signal "activate" */
659 g_signal_connect_after (G_OBJECT (view_account_action),
661 G_CALLBACK (on_show_account_action_toggled),
664 /* Create the items for the Tools->Send&Receive submenu */
665 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
666 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
667 display_name, NULL, NULL);
668 gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
670 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
671 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
672 gtk_ui_manager_add_ui (parent_priv->ui_manager,
674 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
677 GTK_UI_MANAGER_MENUITEM,
679 g_free (refresh_action_name);
681 g_signal_connect_data (G_OBJECT (refresh_account_action),
683 G_CALLBACK (on_refresh_account_action_activated),
684 g_strdup (account_data->account_name),
685 (GClosureNotify) g_free,
688 /* Create item and add it to the send&receive
689 CSM. If there is only one account then
691 if (priv->accounts_popup) {
692 GtkWidget *label = gtk_label_new(NULL);
693 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
694 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
696 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
697 gtk_label_set_markup (GTK_LABEL (label), escaped);
702 gtk_label_set_text (GTK_LABEL (label), display_name);
705 item = gtk_menu_item_new ();
706 gtk_container_add (GTK_CONTAINER (item), label);
708 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
709 g_signal_connect_data (G_OBJECT (item),
711 G_CALLBACK (on_send_receive_csm_activated),
712 g_strdup (account_data->account_name),
713 (GClosureNotify) g_free,
720 g_free (display_name);
723 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
725 /* We cannot do this in the loop above because this relies on the action
726 * group being inserted. This makes the default account appear in bold.
727 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
728 for (i = 0; i < num_accounts; i++) {
729 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
731 if(account_data->account_name && default_account &&
732 strcmp (account_data->account_name, default_account) == 0) {
733 gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
735 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
736 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
740 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
741 if (GTK_IS_LABEL (child)) {
742 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
743 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
744 gtk_label_set_markup (GTK_LABEL (child), bold_name);
749 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
750 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
754 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
755 if (GTK_IS_LABEL (child)) {
756 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
757 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
758 gtk_label_set_markup (GTK_LABEL (child), bold_name);
766 modest_account_mgr_free_account_data (mgr, account_data);
769 if (priv->accounts_popup) {
770 /* Mandatory in order to view the menu contents */
771 gtk_widget_show_all (priv->accounts_popup);
773 /* Setup tap_and_hold just if was not done before*/
774 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
775 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
779 g_slist_free (accounts);
780 g_free (default_account);
783 /* Make sure that at least one account is viewed if there are any
784 * accounts, for instance when adding the first account: */
785 set_at_least_one_account_visible (self);
789 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
791 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
792 gtk_scrolled_window_add_with_viewport
793 (GTK_SCROLLED_WINDOW(win), widget);
795 gtk_container_add (GTK_CONTAINER(win),
806 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
808 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
810 GList *oerrsignals = priv->queue_err_signals;
811 while (oerrsignals) {
812 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
813 g_signal_handler_disconnect (esignal->queue, esignal->signal);
814 g_slice_free (QueueErrorSignal, esignal);
815 oerrsignals = g_list_next (oerrsignals);
817 g_list_free (priv->queue_err_signals);
818 priv->queue_err_signals = NULL;
823 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
825 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
828 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
832 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
834 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
836 /* Update visibility */
839 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
843 modest_main_window_disconnect_signals (ModestWindow *self)
845 ModestMainWindowPrivate *priv;
846 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
848 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
849 priv->sighandlers = NULL;
853 connect_signals (ModestMainWindow *self)
855 ModestWindowPrivate *parent_priv;
856 ModestMainWindowPrivate *priv;
859 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
860 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
865 modest_signal_mgr_connect (priv->sighandlers,
866 G_OBJECT(priv->folder_view), "key-press-event",
867 G_CALLBACK(on_inner_widgets_key_pressed), self);
869 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "folder_selection_changed",
870 G_CALLBACK (modest_main_window_on_folder_selection_changed), self);
872 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
873 G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), self);
875 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event",
876 G_CALLBACK (on_folder_view_focus_in), self);
878 /* Folder view CSM */
879 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
880 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
881 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
882 G_CALLBACK(_folder_view_csm_menu_activated),
886 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
887 G_CALLBACK(modest_ui_actions_on_header_selected), self);
889 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
890 G_CALLBACK(modest_ui_actions_on_header_activated), self);
892 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
893 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
895 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
896 G_CALLBACK(on_inner_widgets_key_pressed), self);
898 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
899 G_CALLBACK(on_msg_count_changed), self);
901 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
902 G_CALLBACK (on_header_view_focus_in), self);
904 modest_signal_mgr_connect (priv->sighandlers,
905 G_OBJECT (priv->header_view),
907 G_CALLBACK (on_updating_msg_list),
910 /* Header view CSM */
911 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
912 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
914 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
915 G_CALLBACK(_header_view_csm_menu_activated),
920 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
921 G_CALLBACK (modest_main_window_window_state_event),
924 /* Mail Operation Queue */
926 modest_signal_mgr_connect (priv->sighandlers,
927 G_OBJECT (modest_runtime_get_mail_operation_queue ()),
929 G_CALLBACK (on_queue_changed), self);
931 /* Track changes in the device name */
933 modest_signal_mgr_connect (priv->sighandlers,
934 G_OBJECT(modest_runtime_get_conf ()),
936 G_CALLBACK (on_configuration_key_changed),
939 /* Track account changes. We need to refresh the toolbar */
941 modest_signal_mgr_connect (priv->sighandlers,
942 G_OBJECT (modest_runtime_get_account_store ()),
944 G_CALLBACK (on_account_inserted),
947 modest_signal_mgr_connect (priv->sighandlers,
948 G_OBJECT (modest_runtime_get_account_store ()),
950 G_CALLBACK (on_account_removed),
953 /* We need to refresh the send & receive menu to change the bold
954 * account when the default account changes. */
956 modest_signal_mgr_connect (priv->sighandlers,
957 G_OBJECT (modest_runtime_get_account_mgr ()),
958 "default_account_changed",
959 G_CALLBACK (on_default_account_changed),
964 modest_signal_mgr_connect (priv->sighandlers,
965 G_OBJECT (modest_runtime_get_account_store()),
966 "password_requested",
967 G_CALLBACK (modest_ui_actions_on_password_requested),
972 /** Idle handler, to send/receive at startup .*/
974 sync_accounts_cb (ModestMainWindow *win)
976 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
977 return FALSE; /* Do not call this idle handler again. */
982 on_hildon_program_is_topmost_notify(GObject *self,
983 GParamSpec *propert_param, gpointer user_data)
985 HildonProgram *app = HILDON_PROGRAM (self);
988 ModestWindow* self = MODEST_WINDOW(user_data);
991 /* Note that use of hildon_program_set_can_hibernate()
992 * is generally referred to as "setting the killable flag",
993 * though hibernation does not seem equal to death.
996 if (hildon_program_get_is_topmost (app)) {
997 /* Prevent hibernation when the progam comes to the foreground,
998 * because hibernation should only happen when the application
999 * is in the background: */
1000 hildon_program_set_can_hibernate (app, FALSE);
1002 /* Allow hibernation if the program has gone to the background: */
1004 /* However, prevent hibernation while the settings are being changed: */
1005 const gboolean hibernation_prevented =
1006 modest_window_mgr_get_hibernation_is_prevented (
1007 modest_runtime_get_window_mgr ());
1009 if (hibernation_prevented)
1010 hildon_program_set_can_hibernate (app, FALSE);
1012 /* Allow hibernation, after saving the state: */
1013 modest_osso_save_state();
1014 hildon_program_set_can_hibernate (app, TRUE);
1021 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1023 GtkWidget *folder_win = (GtkWidget *) user_data;
1024 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1026 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1027 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1028 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
1030 gtk_widget_show (GTK_WIDGET (priv->folder_view));
1032 /* Connect signals */
1033 connect_signals (MODEST_MAIN_WINDOW (self));
1035 /* Set account store */
1036 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1037 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1039 /* Load previous osso state, for instance if we are being restored from
1041 modest_osso_load_state ();
1043 /* Restore window & widget settings */
1044 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1046 /* /\* The UI spec wants us to show a connection dialog when the application is */
1047 /* * started by the user, if there is no connection. */
1048 /* * Do this before showing the account wizard, */
1049 /* * because wizard needs a connection to discover capabilities. *\/ */
1050 /* modest_platform_connect_and_wait (GTK_WINDOW (self), NULL); */
1052 /* Check if accounts exist and show the account wizard if not */
1053 gboolean accounts_exist =
1054 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1056 if (!accounts_exist) {
1057 /* This is necessary to have the main window shown behind the dialog
1058 It's an ugly hack... jschmid */
1059 gtk_widget_show_all(GTK_WIDGET(self));
1060 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1063 GtkAction *send_receive_all;
1064 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1065 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1066 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1067 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1068 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1069 modest_account_mgr_free_account_names (accounts);
1070 update_menus (MODEST_MAIN_WINDOW (self));
1075 modest_main_window_new (void)
1077 ModestMainWindow *self = NULL;
1078 ModestMainWindowPrivate *priv = NULL;
1079 ModestWindowPrivate *parent_priv = NULL;
1080 GtkWidget *folder_win = NULL;
1081 ModestDimmingRulesGroup *menu_rules_group = NULL;
1082 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1083 GtkActionGroup *action_group = NULL;
1084 GError *error = NULL;
1085 ModestConf *conf = NULL;
1086 GtkAction *action = NULL;
1087 GdkPixbuf *window_icon;
1089 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1090 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1091 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1093 parent_priv->ui_manager = gtk_ui_manager_new();
1094 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1096 action_group = gtk_action_group_new ("ModestMainWindowActions");
1097 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1099 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1100 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1102 /* Add common actions */
1103 gtk_action_group_add_actions (action_group,
1104 modest_action_entries,
1105 G_N_ELEMENTS (modest_action_entries),
1108 gtk_action_group_add_actions (action_group,
1109 modest_folder_view_action_entries,
1110 G_N_ELEMENTS (modest_folder_view_action_entries),
1113 gtk_action_group_add_actions (action_group,
1114 modest_header_view_action_entries,
1115 G_N_ELEMENTS (modest_header_view_action_entries),
1118 gtk_action_group_add_toggle_actions (action_group,
1119 modest_toggle_action_entries,
1120 G_N_ELEMENTS (modest_toggle_action_entries),
1123 gtk_action_group_add_toggle_actions (action_group,
1124 modest_main_window_toggle_action_entries,
1125 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1128 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1129 g_object_unref (action_group);
1131 /* Load the UI definition */
1132 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1133 MODEST_UIDIR "modest-main-window-ui.xml", &error);
1134 if (error != NULL) {
1135 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1136 g_error_free (error);
1140 /* Add common dimming rules */
1141 modest_dimming_rules_group_add_rules (menu_rules_group,
1142 modest_main_window_menu_dimming_entries,
1143 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1144 MODEST_WINDOW (self));
1145 modest_dimming_rules_group_add_rules (toolbar_rules_group,
1146 modest_main_window_toolbar_dimming_entries,
1147 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1148 MODEST_WINDOW (self));
1150 /* Insert dimming rules group for this window */
1151 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1152 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1153 g_object_unref (menu_rules_group);
1154 g_object_unref (toolbar_rules_group);
1156 /* Add accelerators */
1157 gtk_window_add_accel_group (GTK_WINDOW (self),
1158 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1160 /* Menubar. Update the state of some toggles */
1161 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1162 conf = modest_runtime_get_conf ();
1163 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1164 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1165 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1166 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1167 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1168 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1169 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1170 modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1171 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1172 gtk_widget_show (parent_priv->menubar);
1174 /* Get device name */
1175 modest_maemo_utils_get_device_name ();
1179 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1180 if (!priv->header_view)
1181 g_printerr ("modest: cannot instantiate header view\n");
1182 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1183 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1184 MODEST_CONF_HEADER_VIEW_KEY);
1186 /* Other style properties of header view */
1187 g_object_set (G_OBJECT (priv->header_view),
1188 "rules-hint", FALSE,
1190 /* gtk_widget_show (priv->header_view); */
1193 priv->empty_view = create_empty_view ();
1194 gtk_widget_show (priv->empty_view);
1196 /* Create scrolled windows */
1197 folder_win = gtk_scrolled_window_new (NULL, NULL);
1198 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1199 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1201 GTK_POLICY_AUTOMATIC);
1202 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1204 GTK_POLICY_AUTOMATIC);
1205 /* gtk_widget_show (priv->contents_widget); */
1208 priv->main_paned = gtk_hpaned_new ();
1209 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1210 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1211 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1213 /* putting it all together... */
1214 priv->main_vbox = gtk_vbox_new (FALSE, 6);
1215 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1216 gtk_widget_show (priv->main_vbox);
1218 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1220 HildonProgram *app = hildon_program_get_instance ();
1221 hildon_program_add_window (app, HILDON_WINDOW (self));
1223 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1224 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1226 g_signal_connect (G_OBJECT(self), "show",
1227 G_CALLBACK (modest_main_window_on_show), folder_win);
1229 /* Set window icon */
1230 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1232 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1233 g_object_unref (window_icon);
1236 /* Dont't restore settings here,
1237 * because it requires a gtk_widget_show(),
1238 * and we don't want to do that until later,
1239 * so that the UI is not visible for non-menu D-Bus activation.
1241 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1243 return MODEST_WINDOW(self);
1247 modest_main_window_set_style (ModestMainWindow *self,
1248 ModestMainWindowStyle style)
1250 ModestMainWindowPrivate *priv;
1251 ModestWindowPrivate *parent_priv;
1255 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1257 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1258 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1260 /* no change -> nothing to do */
1261 if (priv->style == style)
1264 /* Get toggle button and update the state if needed. This will
1265 happen only when the set_style is not invoked from the UI,
1266 for example when it's called from widget memory */
1267 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1268 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1269 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1270 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1271 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1272 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1273 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1276 priv->style = style;
1278 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1279 /* Remove main paned */
1280 g_object_ref (priv->main_paned);
1281 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1283 /* Reparent the contents widget to the main vbox */
1284 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1287 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1288 /* Remove header view */
1289 g_object_ref (priv->contents_widget);
1290 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1292 /* Reparent the main paned */
1293 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1294 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1298 g_return_if_reached ();
1301 /* Let header view grab the focus if it's being shown */
1302 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1303 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1305 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1308 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1311 ModestMainWindowStyle
1312 modest_main_window_get_style (ModestMainWindow *self)
1314 ModestMainWindowPrivate *priv;
1316 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1318 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1325 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1327 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1328 ModestWindowPrivate *parent_priv;
1329 ModestWindowMgr *mgr;
1330 gboolean is_fullscreen;
1331 GtkAction *fs_toggle_action;
1334 mgr = modest_runtime_get_window_mgr ();
1336 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1338 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1340 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1341 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1342 if (is_fullscreen != active) {
1343 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1352 set_homogeneous (GtkWidget *widget,
1355 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1356 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1360 modest_main_window_show_toolbar (ModestWindow *self,
1361 gboolean show_toolbar)
1363 ModestMainWindowPrivate *priv = NULL;
1364 ModestWindowPrivate *parent_priv = NULL;
1365 GtkWidget *reply_button = NULL, *menu = NULL;
1366 GtkWidget *placeholder = NULL;
1368 const gchar *action_name;
1371 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1372 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1373 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1375 /* Set optimized view status */
1376 priv->optimized_view = !show_toolbar;
1378 if (!parent_priv->toolbar) {
1379 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1381 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1383 /* Set homogeneous toolbar */
1384 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1385 set_homogeneous, NULL);
1387 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1388 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1389 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1390 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1391 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1392 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1393 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1394 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1396 /* Add ProgressBar (Transfer toolbar) */
1397 priv->progress_bar = modest_progress_bar_widget_new ();
1398 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1399 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1400 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1401 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1402 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1404 /* Connect cancel 'clicked' signal to abort progress mode */
1405 g_signal_connect(priv->cancel_toolitem, "clicked",
1406 G_CALLBACK(cancel_progressbar),
1409 /* Add it to the observers list */
1410 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1413 hildon_window_add_toolbar (HILDON_WINDOW (self),
1414 GTK_TOOLBAR (parent_priv->toolbar));
1416 /* Set reply button tap and hold menu */
1417 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1418 "/ToolBar/ToolbarMessageReply");
1419 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1420 "/ToolbarReplyCSM");
1421 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1423 /* Set send & receive button tap and hold menu */
1424 update_menus (MODEST_MAIN_WINDOW (self));
1428 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1429 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1430 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1432 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1433 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1435 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1439 /* Update also the actions (to update the toggles in the
1440 menus), we have to do it manually because some other window
1441 of the same time could have changed it (remember that the
1442 toolbar fullscreen mode is shared by all the windows of the
1444 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1445 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1447 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1449 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1450 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1455 on_account_inserted (TnyAccountStore *accoust_store,
1456 TnyAccount *account,
1459 update_menus (MODEST_MAIN_WINDOW (user_data));
1463 on_default_account_changed (ModestAccountMgr* mgr,
1466 update_menus (MODEST_MAIN_WINDOW (user_data));
1470 on_account_removed (TnyAccountStore *accoust_store,
1471 TnyAccount *account,
1474 update_menus (MODEST_MAIN_WINDOW (user_data));
1478 * This function manages the key events used to navigate between
1479 * header and folder views (when the window is in split view)
1482 * -------------------------------------------------
1483 * HeaderView GDK_Left Move focus to folder view
1484 * FolderView GDK_Right Move focus to header view
1486 * There is no need to scroll to selected row, the widgets will be the
1487 * responsibles of doing that (probably managing the focus-in event
1490 on_inner_widgets_key_pressed (GtkWidget *widget,
1494 ModestMainWindowPrivate *priv;
1496 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1498 /* Do nothing if we're in SIMPLE style */
1499 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1502 if (MODEST_IS_HEADER_VIEW (widget)) {
1503 if (event->keyval == GDK_Left)
1504 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1505 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1506 guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1507 if (selected_headers > 1) {
1508 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1512 } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1513 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1519 set_alignment (GtkWidget *widget,
1522 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1523 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1527 create_empty_view (void)
1529 GtkLabel *label = NULL;
1530 GtkWidget *align = NULL;
1532 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1533 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1534 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1535 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1537 return GTK_WIDGET(align);
1541 * Free the returned string
1544 get_gray_color_markup (GtkWidget *styled_widget)
1546 gchar *gray_color_markup;
1548 /* Obtain the secondary text color. We need a realized widget, that's why
1549 we get styled_widget from outside */
1550 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1552 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1553 gray_color_markup = modest_text_utils_get_color_string (&color);
1555 gray_color_markup = g_strdup ("#BBBBBB");
1557 return gray_color_markup;
1561 * Free the returned string
1564 create_device_name_visual_string (const gchar *device_name,
1565 const gchar *gray_color_markup)
1569 /* We have to use "" to fill the %s of the translation. We can
1570 not just use the device name because the device name is
1571 shown in a different color, so it could not be included
1572 into the <span> tag */
1573 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1574 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1584 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1586 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1591 gchar *gray_color_markup;
1593 vbox = gtk_vbox_new (FALSE, 0);
1595 gray_color_markup = get_gray_color_markup (styled_widget);
1597 /* Account description: */
1598 if (modest_tny_account_is_virtual_local_folders (account)
1599 || (modest_tny_account_is_memory_card_account (account))) {
1601 /* Get device name */
1602 gchar *device_name = NULL;
1603 if (modest_tny_account_is_virtual_local_folders (account))
1604 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1605 MODEST_CONF_DEVICE_NAME, NULL);
1607 device_name = g_strdup (tny_account_get_name (account));
1609 label = create_device_name_visual_string ((const gchar *) device_name,
1610 (const gchar *) gray_color_markup);
1611 label_w = gtk_label_new (NULL);
1612 gtk_label_set_markup (GTK_LABEL (label_w), label);
1613 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1614 g_free (device_name);
1617 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1618 gtk_box_pack_start (GTK_BOX (vbox),
1619 gtk_label_new (tny_account_get_name (account)),
1622 /* Other accounts, such as IMAP and POP: */
1627 /* Put proto in uppercase */
1628 proto = g_string_new (tny_account_get_proto (account));
1629 proto = g_string_ascii_up (proto);
1631 /* note: mcen_fi_localroot_description is something like "%s account"
1632 * however, we should display "%s account: %s"... therefore, ugly tmp */
1633 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1634 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1635 gray_color_markup, tmp, tny_account_get_name (account));
1638 label_w = gtk_label_new (NULL);
1639 gtk_label_set_markup (GTK_LABEL (label_w), label);
1640 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1641 g_string_free (proto, TRUE);
1647 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1648 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1649 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1650 modest_tny_folder_store_get_message_count (folder_store));
1651 label_w = gtk_label_new (NULL);
1652 gtk_label_set_markup (GTK_LABEL (label_w), label);
1653 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1657 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1659 _("mcen_fi_rootfolder_folders"),
1660 modest_tny_folder_store_get_folder_count (folder_store));
1661 label_w = gtk_label_new (NULL);
1662 gtk_label_set_markup (GTK_LABEL (label_w), label);
1663 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1667 if (modest_tny_account_is_virtual_local_folders (account)
1668 || modest_tny_account_is_memory_card_account (account)) {
1670 gchar *size = modest_text_utils_get_display_size (
1671 modest_tny_folder_store_get_local_size (folder_store));
1673 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1674 gray_color_markup, _("mcen_fi_rootfolder_size"),
1678 label_w = gtk_label_new (NULL);
1679 gtk_label_set_markup (GTK_LABEL (label_w), label);
1680 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1682 } else if (TNY_IS_ACCOUNT(folder_store)) {
1683 TnyAccount *account = TNY_ACCOUNT(folder_store);
1685 time_t last_updated;
1686 const gchar *last_updated_string;
1687 /* Get last updated from configuration */
1688 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (),
1689 tny_account_get_id (account));
1691 if (last_updated > 0)
1692 last_updated_string = modest_text_utils_get_display_date(last_updated);
1694 last_updated_string = g_strdup (_("mcen_va_never"));
1696 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1697 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1698 label_w = gtk_label_new (NULL);
1699 gtk_label_set_markup (GTK_LABEL (label_w), label);
1700 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1704 g_free (gray_color_markup);
1707 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1713 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1715 ModestMainWindowPrivate *priv = NULL;
1717 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1719 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1721 return priv->send_receive_in_progress;
1725 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1727 GtkAction *action = NULL;
1728 GtkWidget *widget = NULL;
1729 ModestMainWindowPrivate *priv = NULL;
1731 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1732 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1734 priv->send_receive_in_progress = TRUE;
1736 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1737 gtk_action_set_sensitive (action, FALSE);
1738 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1739 /* gtk_action_set_sensitive (action, FALSE); */
1740 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1741 gtk_widget_set_sensitive (widget, FALSE);
1745 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1747 GtkAction *action = NULL;
1748 GtkWidget *widget = NULL;
1749 ModestMainWindowPrivate *priv = NULL;
1751 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1752 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1754 priv->send_receive_in_progress = FALSE;
1756 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1757 gtk_action_set_sensitive (action, TRUE);
1758 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1759 /* gtk_action_set_sensitive (action, TRUE); */
1760 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1761 gtk_widget_set_sensitive (widget, TRUE);
1766 on_msg_count_changed (ModestHeaderView *header_view,
1768 TnyFolderChange *change,
1769 ModestMainWindow *main_window)
1771 gboolean folder_empty = FALSE;
1772 gboolean all_marked_as_deleted = FALSE;
1773 TnyFolderChangeChanged changed;
1774 ModestMainWindowPrivate *priv;
1776 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1777 g_return_if_fail (TNY_IS_FOLDER(folder));
1778 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1779 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1781 changed = tny_folder_change_get_changed (change);
1783 /* If something changes */
1784 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1785 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1787 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1789 /* Check header removed (hide marked as DELETED headers) */
1790 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1791 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1794 /* Check if all messages are marked to be deleted */
1795 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1796 folder_empty = folder_empty || all_marked_as_deleted ;
1798 /* Set contents style of headers view */
1800 modest_main_window_set_contents_style (main_window,
1801 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1802 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1805 modest_main_window_set_contents_style (main_window,
1806 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1812 modest_main_window_set_contents_style (ModestMainWindow *self,
1813 ModestMainWindowContentsStyle style)
1815 ModestMainWindowPrivate *priv;
1817 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1819 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1821 /* We allow to set the same content style than the previously
1822 set if there are details, because it could happen when we're
1823 selecting different accounts consecutively */
1824 if ((priv->contents_style == style) &&
1825 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1828 /* Remove previous child. Delete it if it was an account
1830 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1832 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1833 g_object_ref (content);
1834 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1835 g_object_ref (priv->empty_view);
1836 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1839 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1842 priv->contents_style = style;
1844 switch (priv->contents_style) {
1845 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1846 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1847 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1850 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1852 /* if we're started without main win, there may not be a folder
1853 * view. this fixes a GLib-Critical */
1854 if (priv->folder_view) {
1855 TnyFolderStore *selected_folderstore =
1856 modest_folder_view_get_selected (priv->folder_view);
1857 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1858 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1859 TNY_ACCOUNT (selected_folderstore));
1861 wrap_in_scrolled_window (priv->contents_widget,
1862 priv->details_widget);
1864 g_object_unref (selected_folderstore);
1865 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1870 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1871 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1872 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1876 g_return_if_reached ();
1880 gtk_widget_show_all (priv->contents_widget);
1883 ModestMainWindowContentsStyle
1884 modest_main_window_get_contents_style (ModestMainWindow *self)
1886 ModestMainWindowPrivate *priv;
1888 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1890 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1891 return priv->contents_style;
1896 on_configuration_key_changed (ModestConf* conf,
1898 ModestConfEvent event,
1899 ModestConfNotificationId id,
1900 ModestMainWindow *self)
1902 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1903 TnyAccount *account = NULL;
1905 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1908 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1911 if (priv->folder_view)
1912 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1914 if (account && TNY_IS_ACCOUNT (account) &&
1915 strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1918 const gchar *device_name;
1919 gchar *new_text, *gray_color_markup;
1922 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1923 label = GTK_LABEL (children->data);
1925 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1926 MODEST_CONF_DEVICE_NAME, NULL);
1928 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));
1929 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1931 gtk_label_set_markup (label, new_text);
1932 gtk_widget_show (GTK_WIDGET (label));
1934 g_free (gray_color_markup);
1936 g_list_free (children);
1938 g_object_unref (account);
1942 set_toolbar_transfer_mode (ModestMainWindow *self)
1944 ModestMainWindowPrivate *priv = NULL;
1946 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1948 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1950 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1952 if (priv->progress_bar_timeout > 0) {
1953 g_source_remove (priv->progress_bar_timeout);
1954 priv->progress_bar_timeout = 0;
1961 set_toolbar_mode (ModestMainWindow *self,
1962 ModestToolBarModes mode)
1964 ModestWindowPrivate *parent_priv = NULL;
1965 ModestMainWindowPrivate *priv = NULL;
1966 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1968 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1970 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1971 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1973 /* In case this was called before the toolbar exists: */
1974 if (!(parent_priv->toolbar))
1977 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1979 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1980 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1981 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1983 /* Sets current toolbar mode */
1984 priv->current_toolbar_mode = mode;
1986 /* Checks the dimming rules */
1987 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1989 /* Show and hide toolbar items */
1991 case TOOLBAR_MODE_NORMAL:
1993 gtk_action_set_visible (sort_action, TRUE);
1995 gtk_action_set_visible (refresh_action, TRUE);
1996 if (priv->progress_toolitem) {
1997 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1998 gtk_widget_hide (priv->progress_toolitem);
2000 if (priv->progress_bar)
2001 gtk_widget_hide (priv->progress_bar);
2004 gtk_action_set_visible (cancel_action, FALSE);
2006 /* Hide toolbar if optimized view is enabled */
2007 if (priv->optimized_view)
2008 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2010 case TOOLBAR_MODE_TRANSFER:
2012 gtk_action_set_visible (sort_action, FALSE);
2014 gtk_action_set_visible (refresh_action, FALSE);
2016 gtk_action_set_visible (cancel_action, TRUE);
2017 if (priv->progress_toolitem) {
2018 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2019 gtk_widget_show (priv->progress_toolitem);
2021 if (priv->progress_bar)
2022 gtk_widget_show (priv->progress_bar);
2024 /* Show toolbar if it's hiden (optimized view ) */
2025 if (priv->optimized_view)
2026 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2029 g_return_if_reached ();
2034 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2036 ModestMainWindowPrivate *priv;
2038 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2039 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2041 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2045 cancel_progressbar (GtkToolButton *toolbutton,
2046 ModestMainWindow *self)
2049 ModestMainWindowPrivate *priv;
2051 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2053 /* Get operation observers and cancel all the operations */
2054 tmp = priv->progress_widgets;
2056 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2057 tmp=g_slist_next(tmp);
2062 observers_empty (ModestMainWindow *self)
2065 ModestMainWindowPrivate *priv;
2066 gboolean is_empty = TRUE;
2067 guint pending_ops = 0;
2069 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2070 tmp = priv->progress_widgets;
2072 /* Check all observers */
2073 while (tmp && is_empty) {
2074 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2075 is_empty = pending_ops == 0;
2077 tmp = g_slist_next(tmp);
2085 * Gets the toolbar mode needed for each mail operation. It stores in
2086 * @mode_changed if the toolbar mode has changed or not
2088 static ModestToolBarModes
2089 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2090 ModestMailOperation *mail_op,
2091 gboolean *mode_changed)
2093 ModestToolBarModes mode;
2094 ModestMainWindowPrivate *priv;
2096 *mode_changed = FALSE;
2097 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2099 /* Get toolbar mode from operation id*/
2100 switch (modest_mail_operation_get_type_operation (mail_op)) {
2101 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2102 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2103 mode = TOOLBAR_MODE_TRANSFER;
2104 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2105 *mode_changed = TRUE;
2108 mode = TOOLBAR_MODE_NORMAL;
2114 on_mail_operation_started (ModestMailOperation *mail_op,
2117 ModestMainWindow *self;
2118 ModestMailOperationTypeOperation op_type;
2119 ModestMainWindowPrivate *priv;
2120 ModestToolBarModes mode;
2122 gboolean mode_changed = FALSE;
2123 TnyAccount *account;
2125 self = MODEST_MAIN_WINDOW (user_data);
2126 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2128 /* Do not show progress for receiving operations if the
2129 account is the local account or the MMC one */
2130 op_type = modest_mail_operation_get_type_operation (mail_op);
2131 account = modest_mail_operation_get_account (mail_op);
2132 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2135 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2136 modest_tny_account_is_memory_card_account (account));
2137 g_object_unref (account);
2142 /* Get toolbar mode from operation id*/
2143 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2145 /* Add operation observers and change toolbar if neccessary*/
2146 tmp = priv->progress_widgets;
2147 if (mode == TOOLBAR_MODE_TRANSFER) {
2149 set_toolbar_transfer_mode(self);
2152 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2154 tmp = g_slist_next (tmp);
2160 on_mail_operation_finished (ModestMailOperation *mail_op,
2163 ModestToolBarModes mode;
2164 ModestMailOperationTypeOperation op_type;
2166 ModestMainWindow *self;
2167 gboolean mode_changed;
2168 TnyAccount *account;
2169 ModestMainWindowPrivate *priv;
2171 self = MODEST_MAIN_WINDOW (user_data);
2172 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2174 /* The mail operation was not added to the progress objects if
2175 the account was the local account or the MMC one */
2176 op_type = modest_mail_operation_get_type_operation (mail_op);
2177 account = modest_mail_operation_get_account (mail_op);
2178 if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2181 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2182 modest_tny_account_is_memory_card_account (account));
2183 g_object_unref (account);
2188 /* Get toolbar mode from operation id*/
2189 mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2191 /* Change toolbar mode */
2192 tmp = priv->progress_widgets;
2193 if (mode == TOOLBAR_MODE_TRANSFER) {
2195 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2197 tmp = g_slist_next (tmp);
2200 /* If no more operations are being observed, NORMAL mode is enabled again */
2201 if (observers_empty (self)) {
2202 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2208 on_queue_changed (ModestMailOperationQueue *queue,
2209 ModestMailOperation *mail_op,
2210 ModestMailOperationQueueNotification type,
2211 ModestMainWindow *self)
2213 ModestMainWindowPrivate *priv;
2215 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2217 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2218 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2220 "operation-started",
2221 G_CALLBACK (on_mail_operation_started),
2223 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2225 "operation-finished",
2226 G_CALLBACK (on_mail_operation_finished),
2228 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2229 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2231 "operation-started");
2232 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2234 "operation-finished");
2239 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2241 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2244 /* Get account data */
2245 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2246 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2248 /* Set the new visible & active account */
2249 if (acc_data && acc_data->store_account) {
2250 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2251 acc_data->store_account->account_name);
2252 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2253 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2254 if (action != NULL) {
2255 if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2256 modest_maemo_toggle_action_set_active_block_notify (
2257 GTK_TOGGLE_ACTION (action),
2263 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2268 modest_account_mgr_free_account_data (mgr, acc_data);
2271 /* Make sure that at least one account is "viewed": */
2273 set_at_least_one_account_visible(ModestMainWindow *self)
2275 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2276 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2278 if (!(priv->folder_view)) {
2279 /* It is too early to do this. */
2283 const gchar *active_server_account_name =
2284 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2286 if (!active_server_account_name ||
2287 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2289 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2290 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2291 if (default_modest_name) {
2292 set_account_visible (self, default_modest_name);
2293 } else if (first_modest_name) {
2294 set_account_visible (self, first_modest_name);
2296 g_free (first_modest_name);
2297 g_free (default_modest_name);
2302 on_show_account_action_toggled (GtkToggleAction *action,
2305 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2307 const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2308 if (gtk_toggle_action_get_active (action))
2309 set_account_visible (self, acc_name);
2313 refresh_account (const gchar *account_name)
2317 /* win must already exists here, obviously */
2318 win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2321 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2325 /* If account_name == NULL, we must update all (option All) */
2327 modest_ui_actions_do_send_receive_all (win);
2329 modest_ui_actions_do_send_receive (account_name, win);
2334 on_refresh_account_action_activated (GtkAction *action,
2337 refresh_account ((const gchar*) user_data);
2341 on_send_receive_csm_activated (GtkMenuItem *item,
2344 refresh_account ((const gchar*) user_data);
2348 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2350 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2352 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2358 on_folder_view_focus_in (GtkWidget *widget,
2359 GdkEventFocus *event,
2362 ModestMainWindow *main_window = NULL;
2364 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2365 main_window = MODEST_MAIN_WINDOW (userdata);
2367 /* Update toolbar dimming state */
2368 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2374 on_header_view_focus_in (GtkWidget *widget,
2375 GdkEventFocus *event,
2378 ModestMainWindow *main_window = NULL;
2379 ModestMainWindowPrivate *priv = NULL;
2381 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2382 main_window = MODEST_MAIN_WINDOW (userdata);
2383 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
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;