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>
34 #include <tny-maemo-conic-device.h>
35 #include "modest-hildon-includes.h"
36 #include "modest-defs.h"
39 #include "widgets/modest-main-window.h"
40 #include "widgets/modest-msg-edit-window.h"
41 #include "widgets/modest-account-view-window.h"
42 #include "modest-runtime.h"
43 #include "modest-account-mgr-helpers.h"
44 #include "modest-platform.h"
45 #include "modest-widget-memory.h"
46 #include "modest-window-priv.h"
47 #include "modest-main-window-ui.h"
48 #include "modest-main-window-ui-dimming.h"
49 #include "modest-account-mgr.h"
50 #include "modest-tny-account.h"
51 #include "modest-conf.h"
52 #include <modest-maemo-utils.h>
53 #include "modest-tny-platform-factory.h"
54 #include "modest-tny-msg.h"
55 #include "modest-mail-operation.h"
56 #include "modest-icon-names.h"
57 #include "modest-progress-bar-widget.h"
58 #include "modest-text-utils.h"
59 #include "modest-ui-dimming-manager.h"
60 #include "maemo/modest-osso-state-saving.h"
62 #ifdef MODEST_HILDON_VERSION_0
63 #include <hildon-widgets/hildon-program.h>
65 #include <hildon/hildon-program.h>
66 #endif /*MODEST_HILDON_VERSION_0*/
68 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
75 /* 'private'/'protected' functions */
76 static void modest_main_window_class_init (ModestMainWindowClass *klass);
77 static void modest_main_window_init (ModestMainWindow *obj);
78 static void modest_main_window_finalize (GObject *obj);
79 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
80 GdkEventWindowState *event,
83 static void connect_signals (ModestMainWindow *self);
85 static void restore_settings (ModestMainWindow *self);
86 static void save_state (ModestWindow *self);
88 static void modest_main_window_show_toolbar (ModestWindow *window,
89 gboolean show_toolbar);
91 static void cancel_progressbar (GtkToolButton *toolbutton,
92 ModestMainWindow *self);
94 static void on_queue_changed (ModestMailOperationQueue *queue,
95 ModestMailOperation *mail_op,
96 ModestMailOperationQueueNotification type,
97 ModestMainWindow *self);
99 static void on_account_update (TnyAccountStore *account_store,
100 const gchar *account_name,
103 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
107 static void on_configuration_key_changed (ModestConf* conf,
109 ModestConfEvent event,
110 ModestMainWindow *self);
112 static void set_toolbar_mode (ModestMainWindow *self,
113 ModestToolBarModes mode);
115 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
117 static void on_show_account_action_activated (GtkAction *action,
120 static void on_refresh_account_action_activated (GtkAction *action,
123 static void on_send_receive_csm_activated (GtkMenuItem *item,
127 _on_msg_count_changed (ModestHeaderView *header_view,
129 TnyFolderChange *change,
130 ModestMainWindow *main_window);
133 static GtkWidget * create_empty_view (void);
135 /* list my signals */
142 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
143 struct _ModestMainWindowPrivate {
144 GtkWidget *msg_paned;
145 GtkWidget *main_paned;
146 GtkWidget *main_vbox;
147 GtkWidget *contents_widget;
148 GtkWidget *empty_view;
150 /* Progress observers */
151 GtkWidget *progress_bar;
152 GSList *progress_widgets;
155 GtkWidget *progress_toolitem;
156 GtkWidget *cancel_toolitem;
157 GtkWidget *sort_toolitem;
158 GtkWidget *refresh_toolitem;
159 ModestToolBarModes current_toolbar_mode;
161 /* Merge ids used to add/remove accounts to the ViewMenu*/
162 GByteArray *merge_ids;
164 /* On-demand widgets */
165 GtkWidget *accounts_popup;
166 GtkWidget *details_widget;
168 /* Optimized view enabled */
169 gboolean optimized_view;
171 /* Optimized view enabled */
172 gboolean send_receive_in_progress;
174 ModestHeaderView *header_view;
175 ModestFolderView *folder_view;
177 ModestMainWindowStyle style;
178 ModestMainWindowContentsStyle contents_style;
180 guint progress_bar_timeout;
182 /* Signal handler UIDs */
183 gint queue_changed_handler_uid;
185 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
186 MODEST_TYPE_MAIN_WINDOW, \
187 ModestMainWindowPrivate))
189 typedef struct _GetMsgAsyncHelper {
190 ModestMainWindowPrivate *main_window_private;
192 ModestTnyMsgReplyType reply_type;
193 ModestTnyMsgForwardType forward_type;
200 static GtkWindowClass *parent_class = NULL;
203 /* Private actions */
204 /* This is the context sensitive menu: */
205 static const GtkActionEntry modest_folder_view_action_entries [] = {
207 /* Folder View CSM actions */
208 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
209 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
210 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, NULL },
211 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
212 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
213 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
216 static const GtkActionEntry modest_header_view_action_entries [] = {
218 /* Header View CSM actions */
219 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
220 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
221 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
222 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
223 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
224 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
225 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
226 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete) },
227 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, NULL },
228 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
231 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
232 { "ToolbarToggleView", MODEST_STOCK_SPLIT_VIEW, N_("gqn_toolb_rss_fldonoff"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), FALSE },
235 /************************************************************************/
238 modest_main_window_get_type (void)
240 static GType my_type = 0;
242 static const GTypeInfo my_info = {
243 sizeof(ModestMainWindowClass),
244 NULL, /* base init */
245 NULL, /* base finalize */
246 (GClassInitFunc) modest_main_window_class_init,
247 NULL, /* class finalize */
248 NULL, /* class data */
249 sizeof(ModestMainWindow),
251 (GInstanceInitFunc) modest_main_window_init,
254 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
262 modest_main_window_class_init (ModestMainWindowClass *klass)
264 GObjectClass *gobject_class;
265 gobject_class = (GObjectClass*) klass;
266 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
268 parent_class = g_type_class_peek_parent (klass);
269 gobject_class->finalize = modest_main_window_finalize;
271 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
273 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
274 modest_window_class->save_state_func = save_state;
278 modest_main_window_init (ModestMainWindow *obj)
280 ModestMainWindowPrivate *priv;
282 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
284 priv->msg_paned = NULL;
285 priv->main_paned = NULL;
286 priv->main_vbox = NULL;
287 priv->header_view = NULL;
288 priv->folder_view = NULL;
289 priv->contents_widget = NULL;
290 priv->accounts_popup = NULL;
291 priv->details_widget = NULL;
292 priv->empty_view = NULL;
293 priv->progress_widgets = NULL;
294 priv->progress_bar = NULL;
295 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
296 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
297 priv->contents_style = MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS;
298 priv->merge_ids = NULL;
299 priv->optimized_view = FALSE;
300 priv->send_receive_in_progress = FALSE;
301 priv->progress_bar_timeout = 0;
302 priv->queue_changed_handler_uid = 0;
306 modest_main_window_finalize (GObject *obj)
308 ModestMainWindowPrivate *priv;
310 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
312 g_slist_free (priv->progress_widgets);
314 g_byte_array_free (priv->merge_ids, TRUE);
316 if (priv->progress_bar_timeout > 0) {
317 g_source_remove (priv->progress_bar_timeout);
318 priv->progress_bar_timeout = 0;
321 /* Disconnect signal handlers */
322 if (priv->queue_changed_handler_uid)
323 g_signal_handler_disconnect (modest_runtime_get_mail_operation_queue (),
324 priv->queue_changed_handler_uid);
326 G_OBJECT_CLASS(parent_class)->finalize (obj);
330 modest_main_window_get_child_widget (ModestMainWindow *self,
331 ModestWidgetType widget_type)
333 ModestMainWindowPrivate *priv;
336 g_return_val_if_fail (self, NULL);
337 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
340 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
342 switch (widget_type) {
343 case MODEST_WIDGET_TYPE_HEADER_VIEW:
344 widget = (GtkWidget*)priv->header_view; break;
345 case MODEST_WIDGET_TYPE_FOLDER_VIEW:
346 widget = (GtkWidget*)priv->folder_view; break;
351 return widget ? GTK_WIDGET(widget) : NULL;
356 restore_settings (ModestMainWindow *self)
359 ModestMainWindowPrivate *priv;
361 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
363 conf = modest_runtime_get_conf ();
365 modest_widget_memory_restore (conf, G_OBJECT(self),
366 MODEST_CONF_MAIN_WINDOW_KEY);
367 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
368 MODEST_CONF_HEADER_VIEW_KEY);
369 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
370 MODEST_CONF_FOLDER_VIEW_KEY);
371 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
372 MODEST_CONF_MAIN_PANED_KEY);
374 /* We need to force a redraw here in order to get the right
375 position of the horizontal paned separator */
376 gtk_widget_show (GTK_WIDGET (self));
381 save_state (ModestWindow *window)
384 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
385 ModestMainWindowPrivate *priv;
387 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
388 conf = modest_runtime_get_conf ();
390 modest_widget_memory_save (conf,G_OBJECT(self),
391 MODEST_CONF_MAIN_WINDOW_KEY);
392 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
393 MODEST_CONF_MAIN_PANED_KEY);
394 modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
395 MODEST_CONF_HEADER_VIEW_KEY);
396 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
397 MODEST_CONF_FOLDER_VIEW_KEY);
401 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
403 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
404 gtk_scrolled_window_add_with_viewport
405 (GTK_SCROLLED_WINDOW(win), widget);
407 gtk_container_add (GTK_CONTAINER(win),
413 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMainWindow *self)
415 modest_window_save_state (MODEST_WINDOW(self));
421 on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self)
423 /* When going online, do the equivalent of pressing the send/receive button,
424 * as per the specification:
425 * (without the check for >0 accounts, though that is not specified): */
427 TnyDevice *device = tny_account_store_get_device (store);
429 /* Check that we are really online.
430 * This signal should not be emitted when we are not connected,
431 * but it seems to happen sometimes: */
432 if (!tny_device_is_online (device))
435 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
436 printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id);
438 /* Stop the existing send queues: */
439 modest_runtime_remove_all_send_queues ();
441 /* Create the send queues again, using the appropriate transport accounts
442 * for this new connection.
443 * This could be the first time that they are created if this is the first
445 /* TODO: Does this really destroy the TnySendQueues and their threads
446 * We do not want 2 TnySendQueues to exist with the same underlying
447 * outbox directory. */
448 GSList *account_names = modest_account_mgr_account_names (
449 modest_runtime_get_account_mgr(),
450 TRUE /* enabled accounts only */);
451 GSList *iter = account_names;
453 const gchar *account_name = (const gchar*)(iter->data);
455 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (
456 modest_tny_account_store_get_transport_account_for_open_connection
457 (modest_runtime_get_account_store(), account_name));
459 printf ("debug: %s:\n Transport account for %s: %s\n", __FUNCTION__, account_name,
460 tny_account_get_id(TNY_ACCOUNT(account)));
461 modest_runtime_get_send_queue (account);
465 iter = g_slist_next (iter);
468 g_slist_free (account_names);
471 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self));
475 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
477 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
480 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
484 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
486 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
488 /* Update visibility */
491 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
495 connect_signals (ModestMainWindow *self)
497 ModestWindowPrivate *parent_priv;
498 ModestMainWindowPrivate *priv;
501 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
502 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
505 g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
506 G_CALLBACK(on_inner_widgets_key_pressed), self);
507 g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
508 G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
509 g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
510 G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
512 /* Folder view CSM */
513 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
514 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
515 g_signal_connect (G_OBJECT(priv->folder_view), "tap-and-hold",
516 G_CALLBACK(_folder_view_csm_menu_activated),
519 g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
520 G_CALLBACK(modest_ui_actions_on_header_selected), self);
521 g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
522 G_CALLBACK(modest_ui_actions_on_header_activated), self);
523 g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
524 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
525 g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
526 G_CALLBACK(on_inner_widgets_key_pressed), self);
527 g_signal_connect (G_OBJECT(priv->header_view), "msg_count_changed",
528 G_CALLBACK(_on_msg_count_changed), self);
530 /* Header view CSM */
531 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
532 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
533 g_signal_connect (G_OBJECT(priv->header_view), "tap-and-hold",
534 G_CALLBACK(_header_view_csm_menu_activated),
538 g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
539 g_signal_connect (G_OBJECT (self), "window-state-event",
540 G_CALLBACK (modest_main_window_window_state_event),
542 g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
544 /* Mail Operation Queue */
545 priv->queue_changed_handler_uid =
546 g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
547 "queue-changed", G_CALLBACK (on_queue_changed), self);
549 /* Track changes in the device name */
550 g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
551 "key_changed", G_CALLBACK (on_configuration_key_changed),
554 /* Track account changes. We need to refresh the toolbar */
555 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
556 "account_update", G_CALLBACK (on_account_update),
560 g_signal_connect (G_OBJECT (modest_runtime_get_account_store()),
561 "password_requested",
562 G_CALLBACK (modest_ui_actions_on_password_requested), self);
565 g_signal_connect (G_OBJECT(modest_runtime_get_account_store()),
566 "connecting-finished",
567 G_CALLBACK(on_account_store_connecting_finished), self);
571 /** Idle handler, to send/receive at startup .*/
573 sync_accounts_cb (ModestMainWindow *win)
575 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
576 return FALSE; /* Do not call this idle handler again. */
580 static void on_hildon_program_is_topmost_notify(GObject *self,
581 GParamSpec *propert_param, gpointer user_data)
583 HildonProgram *app = HILDON_PROGRAM (self);
586 ModestWindow* self = MODEST_WINDOW(user_data);
589 /* Note that use of hildon_program_set_can_hibernate()
590 * is generally referred to as "setting the killable flag",
591 * though hibernation does not seem equal to death.
594 if (hildon_program_get_is_topmost (app)) {
595 /* Prevent hibernation when the progam comes to the foreground,
596 * because hibernation should only happen when the application
597 * is in the background: */
598 hildon_program_set_can_hibernate (app, FALSE);
600 /* Allow hibernation if the program has gone to the background: */
602 /* However, prevent hibernation while the settings are being changed: */
603 const gboolean hibernation_prevented =
604 modest_window_mgr_get_hibernation_is_prevented (
605 modest_runtime_get_window_mgr ());
607 if (hibernation_prevented)
608 hildon_program_set_can_hibernate (app, FALSE);
610 /* Allow hibernation, after saving the state: */
611 modest_osso_save_state();
612 hildon_program_set_can_hibernate (app, TRUE);
621 modest_main_window_new (void)
623 ModestMainWindow *self = NULL;
624 ModestMainWindowPrivate *priv = NULL;
625 ModestWindowPrivate *parent_priv = NULL;
626 GtkWidget *folder_win = NULL;
627 ModestDimmingRulesGroup *menu_rules_group = NULL;
628 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
629 GtkActionGroup *action_group = NULL;
630 GError *error = NULL;
631 TnyFolderStoreQuery *query = NULL;
632 GdkPixbuf *window_icon = NULL;
633 ModestConf *conf = NULL;
634 GtkAction *action = NULL;
636 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
637 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
638 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
640 parent_priv->ui_manager = gtk_ui_manager_new();
641 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
643 action_group = gtk_action_group_new ("ModestMainWindowActions");
644 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
646 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules");
647 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules");
649 /* Add common actions */
650 gtk_action_group_add_actions (action_group,
651 modest_action_entries,
652 G_N_ELEMENTS (modest_action_entries),
655 gtk_action_group_add_actions (action_group,
656 modest_folder_view_action_entries,
657 G_N_ELEMENTS (modest_folder_view_action_entries),
660 gtk_action_group_add_actions (action_group,
661 modest_header_view_action_entries,
662 G_N_ELEMENTS (modest_header_view_action_entries),
665 gtk_action_group_add_toggle_actions (action_group,
666 modest_toggle_action_entries,
667 G_N_ELEMENTS (modest_toggle_action_entries),
670 gtk_action_group_add_toggle_actions (action_group,
671 modest_main_window_toggle_action_entries,
672 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
675 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
676 g_object_unref (action_group);
678 /* Load the UI definition */
679 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
680 MODEST_UIDIR "modest-main-window-ui.xml", &error);
682 g_warning ("Could not merge modest-ui.xml: %s", error->message);
683 g_error_free (error);
687 /* Add common dimming rules */
688 modest_dimming_rules_group_add_rules (menu_rules_group,
689 modest_main_window_menu_dimming_entries,
690 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
692 modest_dimming_rules_group_add_rules (toolbar_rules_group,
693 modest_main_window_toolbar_dimming_entries,
694 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
697 /* Insert dimming rules group for this window */
698 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
699 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
700 g_object_unref (menu_rules_group);
701 g_object_unref (toolbar_rules_group);
703 /* Add accelerators */
704 gtk_window_add_accel_group (GTK_WINDOW (self),
705 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
707 /* Menubar. Update the state of some toggles */
708 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
709 conf = modest_runtime_get_conf ();
710 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
711 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
712 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
713 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
714 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
715 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
716 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
717 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
718 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
720 /* Get device name */
721 modest_maemo_utils_get_device_name ();
726 /* tny_folder_store_query_new ();
728 tny_folder_store_query_add_item (query, NULL,
729 TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
732 priv->folder_view = MODEST_FOLDER_VIEW(modest_folder_view_new (query));
733 if (!priv->folder_view)
734 g_printerr ("modest: cannot instantiate folder view\n");
735 /* g_object_unref (G_OBJECT (query)); */
737 modest_folder_view_set_style (priv->folder_view,
738 MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
742 MODEST_HEADER_VIEW(modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
743 if (!priv->header_view)
744 g_printerr ("modest: cannot instantiate header view\n");
745 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
748 priv->empty_view = create_empty_view ();
750 /* Create scrolled windows */
751 folder_win = gtk_scrolled_window_new (NULL, NULL);
752 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
753 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
755 GTK_POLICY_AUTOMATIC);
756 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
758 GTK_POLICY_AUTOMATIC);
760 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
761 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view));
764 priv->main_paned = gtk_hpaned_new ();
765 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
766 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
767 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
769 /* putting it all together... */
770 priv->main_vbox = gtk_vbox_new (FALSE, 6);
771 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
773 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
775 /* Set window icon */
776 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
777 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
779 /* Connect signals */
780 connect_signals (self);
782 /* Set account store */
783 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
784 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
786 /* Check if accounts exist and show the account wizard if not */
787 gboolean accounts_exist =
788 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
792 /* This is necessary to have the main window shown behind the dialog
793 It's an ugly hack... jschmid */
794 gtk_widget_show_all(GTK_WIDGET(self));
795 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
798 /* Do send & receive when we are idle */
799 /* TODO: Enable this again. I have commented it out because,
800 * at least in scratchbox, this can cause us to start a second
801 * update (in response to a connection change) when we are already
802 * doing an update (started here, at startup). Tinymail doesn't like that.
805 /* g_idle_add ((GSourceFunc)sync_accounts_cb, self); */
807 HildonProgram *app = hildon_program_get_instance ();
808 hildon_program_add_window (app, HILDON_WINDOW (self));
810 /* Register HildonProgram signal handlers: */
811 /* These are apparently deprecated, according to the
812 * "HildonApp/HildonAppView to HildonProgram/HildonWindow migration guide",
813 * though the API reference does not mention that:
815 g_signal_connect (G_OBJECT(app), "topmost_status_lose",
816 G_CALLBACK (on_hildon_program_save_state), self);
817 g_signal_connect (G_OBJECT(app), "topmost_status_acquire",
818 G_CALLBACK (on_hildon_program_status_acquire), self);
820 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
821 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
823 /* Load previous osso state, for instance if we are being restored from
825 modest_osso_load_state();
827 /* Restore window & widget settings */
828 restore_settings (MODEST_MAIN_WINDOW(self));
830 return MODEST_WINDOW(self);
834 modest_main_window_close_all (ModestMainWindow *self)
837 GtkResponseType response;
839 /* Create the confirmation dialog MSG-NOT308 */
840 note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
841 _("emev_nc_close_windows"),
842 _("mcen_bd_yes"), GTK_RESPONSE_YES,
843 _("mcen_bd_no"), GTK_RESPONSE_NO,
846 response = gtk_dialog_run (GTK_DIALOG (note));
847 gtk_widget_destroy (GTK_WIDGET (note));
849 if (response == GTK_RESPONSE_YES)
857 modest_main_window_set_style (ModestMainWindow *self,
858 ModestMainWindowStyle style)
860 ModestMainWindowPrivate *priv;
861 ModestWindowPrivate *parent_priv;
864 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
866 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
867 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
869 /* no change -> nothing to do */
870 if (priv->style == style)
873 /* Get toggle button */
874 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
878 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
879 /* Remove main paned */
880 g_object_ref (priv->main_paned);
881 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
883 /* Reparent the contents widget to the main vbox */
884 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
886 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
887 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
888 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
891 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
892 /* Remove header view */
893 g_object_ref (priv->contents_widget);
894 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
896 /* Reparent the main paned */
897 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
898 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
900 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
901 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
902 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
906 g_return_if_reached ();
909 /* Let header view grab the focus if it's being shown */
910 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
911 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
913 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
916 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
919 ModestMainWindowStyle
920 modest_main_window_get_style (ModestMainWindow *self)
922 ModestMainWindowPrivate *priv;
924 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
926 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
933 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
935 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
936 ModestWindowPrivate *parent_priv;
937 ModestWindowMgr *mgr;
938 gboolean is_fullscreen;
939 GtkAction *fs_toggle_action;
942 mgr = modest_runtime_get_window_mgr ();
944 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
946 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
948 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
949 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
950 if (is_fullscreen != active) {
951 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
960 set_homogeneous (GtkWidget *widget,
963 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
964 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
968 modest_main_window_show_toolbar (ModestWindow *self,
969 gboolean show_toolbar)
971 ModestMainWindowPrivate *priv = NULL;
972 ModestWindowPrivate *parent_priv = NULL;
973 GtkWidget *reply_button = NULL, *menu = NULL;
974 GtkWidget *placeholder = NULL;
977 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
978 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
979 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
981 /* Set optimized view status */
982 priv->optimized_view = !show_toolbar;
984 if (!parent_priv->toolbar) {
985 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
988 /* Set homogeneous toolbar */
989 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
990 set_homogeneous, NULL);
992 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
993 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
994 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
995 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
996 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
997 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
998 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
999 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1001 /* Add ProgressBar (Transfer toolbar) */
1002 priv->progress_bar = modest_progress_bar_widget_new ();
1003 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1004 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1005 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1006 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1007 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1009 /* Connect cancel 'clicked' signal to abort progress mode */
1010 g_signal_connect(priv->cancel_toolitem, "clicked",
1011 G_CALLBACK(cancel_progressbar),
1014 /* Add it to the observers list */
1015 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1018 hildon_window_add_toolbar (HILDON_WINDOW (self),
1019 GTK_TOOLBAR (parent_priv->toolbar));
1021 /* Set reply button tap and hold menu */
1022 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1023 "/ToolBar/ToolbarMessageReply");
1024 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1025 "/ToolbarReplyCSM");
1026 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1028 /* Set send & receive button tap and hold menu */
1029 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1034 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1035 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1036 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1038 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1039 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1041 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1046 compare_display_names (ModestAccountData *a,
1047 ModestAccountData *b)
1049 return strcmp (a->display_name, b->display_name);
1053 on_account_update (TnyAccountStore *account_store,
1054 const gchar *account_name,
1057 GSList *account_names, *iter, *accounts;
1058 ModestMainWindow *self;
1059 ModestMainWindowPrivate *priv;
1060 ModestWindowPrivate *parent_priv;
1061 ModestAccountMgr *mgr;
1062 gint i, num_accounts;
1063 GtkActionGroup *action_group;
1065 gchar *default_account;
1066 GtkWidget *send_receive_button, *item;
1068 self = MODEST_MAIN_WINDOW (user_data);
1069 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1070 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1072 /* Get enabled account IDs */
1073 mgr = modest_runtime_get_account_mgr ();
1074 account_names = modest_account_mgr_account_names (mgr, TRUE);
1075 iter = account_names;
1079 ModestAccountData *account_data =
1080 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
1081 accounts = g_slist_prepend (accounts, account_data);
1085 g_slist_free (account_names);
1087 /* Order the list of accounts by its display name */
1088 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1089 num_accounts = g_slist_length (accounts);
1091 /* Delete old send&receive popup items. We can not just do a
1092 menu_detach because it does not work well with
1094 if (priv->accounts_popup)
1095 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
1096 (GtkCallback) gtk_widget_destroy, NULL);
1098 /* Delete old entries in the View menu. Do not free groups, it
1100 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1102 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1103 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1104 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
1105 GTK_ACTION_GROUP (groups->data));
1108 if (priv->merge_ids) {
1109 for (i = 0; i < priv->merge_ids->len; i++)
1110 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1111 g_byte_array_free (priv->merge_ids, TRUE);
1113 /* We need to call this in order to ensure
1114 that the new actions are added in the right
1115 order (alphabetical */
1116 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1118 groups = g_list_next (groups);
1120 priv->merge_ids = g_byte_array_sized_new (num_accounts);
1122 /* Get send receive button */
1123 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1124 "/ToolBar/ToolbarSendReceive");
1126 /* Create the menu */
1127 if (num_accounts > 1) {
1128 if (!priv->accounts_popup)
1129 priv->accounts_popup = gtk_menu_new ();
1130 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1131 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1132 g_signal_connect (G_OBJECT (item),
1134 G_CALLBACK (on_send_receive_csm_activated),
1136 item = gtk_separator_menu_item_new ();
1137 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1140 /* Create a new action group */
1141 default_account = modest_account_mgr_get_default_account (mgr);
1142 action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1143 for (i = 0; i < num_accounts; i++) {
1144 gchar *display_name = NULL;
1146 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1148 /* Create display name. The default account is shown differently */
1149 if (default_account && account_data->account_name &&
1150 !(strcmp (default_account, account_data->account_name) == 0)) {
1151 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
1152 account_data->display_name);
1155 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
1156 account_data->display_name);
1159 /* Create action and add it to the action group. The
1160 action name must be the account name, this way we
1161 could know in the handlers the account to show */
1162 if(account_data->account_name) {
1163 gchar* item_name, *refresh_action_name;
1165 GtkAction *view_account_action, *refresh_account_action;
1167 view_account_action = gtk_action_new (account_data->account_name,
1168 display_name, NULL, NULL);
1169 gtk_action_group_add_action (action_group, view_account_action);
1171 /* Add ui from account data. We allow 2^9-1 account
1172 changes in a single execution because we're
1173 downcasting the guint to a guint8 in order to use a
1174 GByteArray, it should be enough */
1175 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1176 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1177 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1178 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1180 "/MenuBar/ViewMenu/ViewMenuAdditions",
1182 account_data->account_name,
1183 GTK_UI_MANAGER_MENUITEM,
1186 /* Connect the action signal "activate" */
1187 g_signal_connect (G_OBJECT (view_account_action),
1189 G_CALLBACK (on_show_account_action_activated),
1192 /* Create the items for the Tools->Send&Receive submenu */
1193 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1194 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
1195 display_name, NULL, NULL);
1196 gtk_action_group_add_action (action_group, refresh_account_action);
1198 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1199 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1200 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1202 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1204 refresh_action_name,
1205 GTK_UI_MANAGER_MENUITEM,
1207 g_free (refresh_action_name);
1209 g_signal_connect_data (G_OBJECT (refresh_account_action),
1211 G_CALLBACK (on_refresh_account_action_activated),
1212 g_strdup (account_data->account_name),
1213 (GClosureNotify) g_free,
1216 /* Create item and add it to the send&receive
1217 CSM. If there is only one account then
1219 if (priv->accounts_popup) {
1220 item = gtk_menu_item_new_with_label (display_name);
1221 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1222 g_signal_connect_data (G_OBJECT (item),
1224 G_CALLBACK (on_send_receive_csm_activated),
1225 g_strdup (account_data->account_name),
1226 (GClosureNotify) g_free,
1233 g_free (display_name);
1234 modest_account_mgr_free_account_data (mgr, account_data);
1236 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1238 if (priv->accounts_popup) {
1239 /* Mandatory in order to view the menu contents */
1240 gtk_widget_show_all (priv->accounts_popup);
1242 /* Setup tap_and_hold just if was not done before*/
1243 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1244 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1248 g_slist_free (accounts);
1249 g_free (default_account);
1253 * This function manages the key events used to navigate between
1254 * header and folder views (when the window is in split view)
1257 * -------------------------------------------------
1258 * HeaderView GDK_Left Move focus to folder view
1259 * FolderView GDK_Right Move focus to header view
1261 * There is no need to scroll to selected row, the widgets will be the
1262 * responsibles of doing that (probably managing the focus-in event
1265 on_inner_widgets_key_pressed (GtkWidget *widget,
1269 ModestMainWindowPrivate *priv;
1271 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1273 /* Do nothing if we're in SIMPLE style */
1274 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1277 if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1278 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1279 else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1280 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1286 set_alignment (GtkWidget *widget,
1289 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1290 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1294 create_empty_view (void)
1296 GtkLabel *label = NULL;
1297 GtkWidget *align = NULL;
1299 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1300 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1301 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1302 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1304 return GTK_WIDGET(align);
1308 create_details_widget (TnyAccount *account)
1313 vbox = gtk_vbox_new (FALSE, 0);
1315 /* Account description: */
1317 if (modest_tny_account_is_virtual_local_folders (account)) {
1318 /* Local folders: */
1320 /* Get device name */
1321 gchar *device_name = modest_conf_get_string (modest_runtime_get_conf(),
1322 MODEST_CONF_DEVICE_NAME, NULL);
1324 label = g_strdup_printf (_("mcen_fi_localroot_description"),
1326 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1327 g_free (device_name);
1330 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1331 gtk_box_pack_start (GTK_BOX (vbox),
1332 gtk_label_new (tny_account_get_name (account)),
1335 /* Other accounts, such as IMAP and POP: */
1340 /* Put proto in uppercase */
1341 proto = g_string_new (tny_account_get_proto (account));
1342 proto = g_string_ascii_up (proto);
1344 /* note: mcen_fi_localroot_description is something like "%s account"
1345 * however, we should display "%s account: %s"... therefore, ugly tmp */
1346 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1347 label = g_strdup_printf ("%s: %s", tmp,tny_account_get_name (account));
1350 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1351 g_string_free (proto, TRUE);
1357 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1358 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"),
1359 modest_tny_folder_store_get_message_count (folder_store));
1360 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1364 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"),
1365 modest_tny_folder_store_get_folder_count (folder_store));
1366 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1370 if (modest_tny_account_is_virtual_local_folders (account)) {
1371 /* FIXME: format size */
1372 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"),
1373 modest_tny_folder_store_get_local_size (folder_store));
1374 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1376 } else if (TNY_IS_ACCOUNT(folder_store)) {
1377 TnyAccount *account = TNY_ACCOUNT(folder_store);
1379 time_t last_updated;
1380 gchar *last_updated_string;
1381 /* Get last updated from configuration */
1382 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (),
1383 tny_account_get_id (account),
1384 MODEST_ACCOUNT_LAST_UPDATED,
1386 if (last_updated > 0)
1387 last_updated_string = modest_text_utils_get_display_date(last_updated);
1389 last_updated_string = g_strdup (_("mcen_va_never"));
1391 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
1392 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1393 g_free (last_updated_string);
1398 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1404 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1406 GtkAction *action = NULL;
1407 GtkWidget *widget = NULL;
1409 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1411 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1412 gtk_action_set_sensitive (action, FALSE);
1413 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1414 /* gtk_action_set_sensitive (action, FALSE); */
1415 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1416 gtk_widget_set_sensitive (widget, FALSE);
1420 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1422 GtkAction *action = NULL;
1423 GtkWidget *widget = NULL;
1425 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1427 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1428 gtk_action_set_sensitive (action, TRUE);
1429 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1430 /* gtk_action_set_sensitive (action, TRUE); */
1431 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1432 gtk_widget_set_sensitive (widget, TRUE);
1437 _on_msg_count_changed (ModestHeaderView *header_view,
1439 TnyFolderChange *change,
1440 ModestMainWindow *main_window)
1442 gboolean folder_empty = FALSE;
1443 TnyFolderChangeChanged changed;
1445 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1446 g_return_if_fail (TNY_IS_FOLDER(folder));
1447 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1449 changed = tny_folder_change_get_changed (change);
1451 /* If something changes */
1452 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1453 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1455 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1457 /* Set contents style of headers view */
1459 modest_main_window_set_contents_style (main_window,
1460 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1463 modest_main_window_set_contents_style (main_window,
1464 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1470 modest_main_window_set_contents_style (ModestMainWindow *self,
1471 ModestMainWindowContentsStyle style)
1473 ModestMainWindowPrivate *priv;
1475 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1477 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1479 /* We allow to set the same content style than the previously
1480 set if there are details, because it could happen when we're
1481 selecting different accounts consecutively */
1482 if ((priv->contents_style == style) &&
1483 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1486 /* Remove previous child. Delete it if it was an account
1488 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1490 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1491 g_object_ref (content);
1492 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1493 g_object_ref (priv->empty_view);
1494 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1497 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1500 priv->contents_style = style;
1502 switch (priv->contents_style) {
1503 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1504 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1506 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1508 /* TODO: show here account details */
1509 TnyFolderStore *selected_folderstore =
1510 modest_folder_view_get_selected (priv->folder_view);
1511 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1512 priv->details_widget = create_details_widget (
1513 TNY_ACCOUNT (selected_folderstore));
1515 wrap_in_scrolled_window (priv->contents_widget,
1516 priv->details_widget);
1520 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1521 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1524 g_return_if_reached ();
1528 gtk_widget_show_all (priv->contents_widget);
1532 on_configuration_key_changed (ModestConf* conf,
1534 ModestConfEvent event,
1535 ModestMainWindow *self)
1537 ModestMainWindowPrivate *priv;
1538 TnyAccount *account;
1540 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1543 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1545 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1548 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1549 if (TNY_IS_ACCOUNT (account) &&
1550 !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1553 const gchar *device_name;
1557 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1558 label = GTK_LABEL (children->data);
1560 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1561 MODEST_CONF_DEVICE_NAME, NULL);
1563 new_text = g_strdup_printf ("%s: %s",
1564 _("mcen_fi_localroot_description"),
1567 gtk_label_set_text (label, new_text);
1568 gtk_widget_show (GTK_WIDGET (label));
1571 g_list_free (children);
1576 set_toolbar_transfer_mode (ModestMainWindow *self)
1578 ModestMainWindowPrivate *priv = NULL;
1580 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1582 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1584 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1586 if (priv->progress_bar_timeout > 0) {
1587 g_source_remove (priv->progress_bar_timeout);
1588 priv->progress_bar_timeout = 0;
1595 set_toolbar_mode (ModestMainWindow *self,
1596 ModestToolBarModes mode)
1598 ModestWindowPrivate *parent_priv = NULL;
1599 ModestMainWindowPrivate *priv = NULL;
1600 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1602 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1604 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1605 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1607 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1609 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1610 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1611 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1613 /* Sets current toolbar mode */
1614 priv->current_toolbar_mode = mode;
1616 /* Show and hide toolbar items */
1618 case TOOLBAR_MODE_NORMAL:
1620 gtk_action_set_visible (sort_action, TRUE);
1622 gtk_action_set_visible (refresh_action, TRUE);
1623 if (priv->progress_toolitem) {
1624 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1625 gtk_widget_hide (priv->progress_toolitem);
1627 if (priv->progress_bar)
1628 gtk_widget_hide (priv->progress_bar);
1631 gtk_action_set_visible (cancel_action, FALSE);
1633 /* Hide toolbar if optimized view is enabled */
1634 if (priv->optimized_view)
1635 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1637 case TOOLBAR_MODE_TRANSFER:
1639 gtk_action_set_visible (sort_action, FALSE);
1641 gtk_action_set_visible (refresh_action, FALSE);
1643 gtk_action_set_visible (cancel_action, TRUE);
1644 if (priv->progress_toolitem) {
1645 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1646 gtk_widget_show (priv->progress_toolitem);
1648 if (priv->progress_bar)
1649 gtk_widget_show (priv->progress_bar);
1651 /* Show toolbar if it's hiden (optimized view ) */
1652 if (priv->optimized_view)
1653 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1656 g_return_if_reached ();
1661 cancel_progressbar (GtkToolButton *toolbutton,
1662 ModestMainWindow *self)
1665 ModestMainWindowPrivate *priv;
1667 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1669 /* Get operation observers and cancel its current operation */
1670 tmp = priv->progress_widgets;
1672 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1673 tmp=g_slist_next(tmp);
1678 observers_empty (ModestMainWindow *self)
1681 ModestMainWindowPrivate *priv;
1682 gboolean is_empty = TRUE;
1683 guint pending_ops = 0;
1685 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1686 tmp = priv->progress_widgets;
1688 /* Check all observers */
1689 while (tmp && is_empty) {
1690 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1691 is_empty = pending_ops == 0;
1693 tmp = g_slist_next(tmp);
1700 on_queue_changed (ModestMailOperationQueue *queue,
1701 ModestMailOperation *mail_op,
1702 ModestMailOperationQueueNotification type,
1703 ModestMainWindow *self)
1705 ModestMainWindowPrivate *priv;
1706 ModestMailOperationTypeOperation op_type;
1707 ModestToolBarModes mode;
1709 gboolean mode_changed = FALSE;
1710 /* ModestMailOperationStatus status; */
1712 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1713 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1715 /* Get toolbar mode from operation id*/
1716 op_type = modest_mail_operation_get_type_operation (mail_op);
1718 case MODEST_MAIL_OPERATION_TYPE_SEND:
1719 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1720 mode = TOOLBAR_MODE_TRANSFER;
1721 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1722 mode_changed = TRUE;
1725 mode = TOOLBAR_MODE_NORMAL;
1730 /* Add operation observers and change toolbar if neccessary*/
1731 tmp = priv->progress_widgets;
1733 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1734 if (mode == TOOLBAR_MODE_TRANSFER) {
1736 set_toolbar_transfer_mode(self);
1738 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1740 tmp = g_slist_next (tmp);
1744 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1745 /* Change toolbar mode */
1746 if (mode == TOOLBAR_MODE_TRANSFER) {
1748 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1750 tmp = g_slist_next (tmp);
1753 /* If no more operations are being observed, NORMAL mode is enabled again */
1754 if (observers_empty (self)) {
1755 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1766 on_show_account_action_activated (GtkAction *action,
1769 ModestAccountData *acc_data;
1770 ModestMainWindow *self;
1771 ModestMainWindowPrivate *priv;
1772 ModestAccountMgr *mgr;
1773 const gchar *acc_name;
1775 self = MODEST_MAIN_WINDOW (user_data);
1776 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1778 /* Get account data */
1779 acc_name = gtk_action_get_name (action);
1780 mgr = modest_runtime_get_account_mgr ();
1781 acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1783 /* Set the new visible & active account */
1784 if (acc_data->store_account) {
1785 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1786 acc_data->store_account->account_name);
1787 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1791 modest_account_mgr_free_account_data (mgr, acc_data);
1795 refresh_account (const gchar *account_name)
1799 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1801 /* If account_name == NULL, we must update all (option All) */
1803 modest_ui_actions_do_send_receive_all (win);
1805 modest_ui_actions_do_send_receive (account_name, win);
1809 on_refresh_account_action_activated (GtkAction *action,
1812 refresh_account ((const gchar*) user_data);
1816 on_send_receive_csm_activated (GtkMenuItem *item,
1819 refresh_account ((const gchar*) user_data);