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, gboolean do_folder_view_too);
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);
136 translate_func (const gchar *msgid,
137 const gchar *domain_name);
140 /* list my signals */
147 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
148 struct _ModestMainWindowPrivate {
149 GtkWidget *msg_paned;
150 GtkWidget *main_paned;
151 GtkWidget *main_vbox;
152 GtkWidget *contents_widget;
153 GtkWidget *empty_view;
155 /* Progress observers */
156 GtkWidget *progress_bar;
157 GSList *progress_widgets;
160 GtkWidget *progress_toolitem;
161 GtkWidget *cancel_toolitem;
162 GtkWidget *sort_toolitem;
163 GtkWidget *refresh_toolitem;
164 ModestToolBarModes current_toolbar_mode;
166 /* Merge ids used to add/remove accounts to the ViewMenu*/
167 GByteArray *merge_ids;
169 /* On-demand widgets */
170 GtkWidget *accounts_popup;
171 GtkWidget *details_widget;
173 /* Optimized view enabled */
174 gboolean optimized_view;
176 /* Optimized view enabled */
177 gboolean send_receive_in_progress;
179 ModestHeaderView *header_view;
180 ModestFolderView *folder_view;
182 ModestMainWindowStyle style;
183 ModestMainWindowContentsStyle contents_style;
185 guint progress_bar_timeout;
187 /* Signal handler UIDs */
188 gint queue_changed_handler_uid;
190 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
191 MODEST_TYPE_MAIN_WINDOW, \
192 ModestMainWindowPrivate))
194 typedef struct _GetMsgAsyncHelper {
195 ModestMainWindowPrivate *main_window_private;
197 ModestTnyMsgReplyType reply_type;
198 ModestTnyMsgForwardType forward_type;
205 static GtkWindowClass *parent_class = NULL;
208 /* Private actions */
209 /* This is the context sensitive menu: */
210 static const GtkActionEntry modest_folder_view_action_entries [] = {
212 /* Folder View CSM actions */
213 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
214 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
215 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, NULL },
216 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
217 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
218 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
221 static const GtkActionEntry modest_header_view_action_entries [] = {
223 /* Header View CSM actions */
224 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
225 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
226 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
227 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
228 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
229 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
230 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
231 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete) },
232 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, NULL },
233 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
236 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
237 { "ToolbarToggleView", MODEST_STOCK_SPLIT_VIEW, N_("gqn_toolb_rss_fldonoff"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), FALSE },
240 /************************************************************************/
243 modest_main_window_get_type (void)
245 static GType my_type = 0;
247 static const GTypeInfo my_info = {
248 sizeof(ModestMainWindowClass),
249 NULL, /* base init */
250 NULL, /* base finalize */
251 (GClassInitFunc) modest_main_window_class_init,
252 NULL, /* class finalize */
253 NULL, /* class data */
254 sizeof(ModestMainWindow),
256 (GInstanceInitFunc) modest_main_window_init,
259 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
267 modest_main_window_class_init (ModestMainWindowClass *klass)
269 GObjectClass *gobject_class;
270 gobject_class = (GObjectClass*) klass;
271 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
273 parent_class = g_type_class_peek_parent (klass);
274 gobject_class->finalize = modest_main_window_finalize;
276 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
278 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
279 modest_window_class->save_state_func = save_state;
283 modest_main_window_init (ModestMainWindow *obj)
285 ModestMainWindowPrivate *priv;
287 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
289 priv->msg_paned = NULL;
290 priv->main_paned = NULL;
291 priv->main_vbox = NULL;
292 priv->header_view = NULL;
293 priv->folder_view = NULL;
294 priv->contents_widget = NULL;
295 priv->accounts_popup = NULL;
296 priv->details_widget = NULL;
297 priv->empty_view = NULL;
298 priv->progress_widgets = NULL;
299 priv->progress_bar = NULL;
300 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
301 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
302 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
303 priv->merge_ids = NULL;
304 priv->optimized_view = FALSE;
305 priv->send_receive_in_progress = FALSE;
306 priv->progress_bar_timeout = 0;
307 priv->queue_changed_handler_uid = 0;
311 modest_main_window_finalize (GObject *obj)
313 ModestMainWindowPrivate *priv;
315 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
317 g_slist_free (priv->progress_widgets);
319 g_byte_array_free (priv->merge_ids, TRUE);
321 if (priv->progress_bar_timeout > 0) {
322 g_source_remove (priv->progress_bar_timeout);
323 priv->progress_bar_timeout = 0;
326 /* Disconnect signal handlers */
327 if (priv->queue_changed_handler_uid)
328 g_signal_handler_disconnect (modest_runtime_get_mail_operation_queue (),
329 priv->queue_changed_handler_uid);
331 G_OBJECT_CLASS(parent_class)->finalize (obj);
335 modest_main_window_get_child_widget (ModestMainWindow *self,
336 ModestWidgetType widget_type)
338 ModestMainWindowPrivate *priv;
341 g_return_val_if_fail (self, NULL);
342 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
345 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
347 switch (widget_type) {
348 case MODEST_WIDGET_TYPE_HEADER_VIEW:
349 widget = (GtkWidget*)priv->header_view; break;
350 case MODEST_WIDGET_TYPE_FOLDER_VIEW:
351 widget = (GtkWidget*)priv->folder_view; break;
356 return widget ? GTK_WIDGET(widget) : NULL;
361 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
364 ModestMainWindowPrivate *priv;
366 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
368 conf = modest_runtime_get_conf ();
370 modest_widget_memory_restore (conf, G_OBJECT(self),
371 MODEST_CONF_MAIN_WINDOW_KEY);
373 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
374 MODEST_CONF_HEADER_VIEW_KEY);
376 if (do_folder_view_too)
377 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
378 MODEST_CONF_FOLDER_VIEW_KEY);
380 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
381 MODEST_CONF_MAIN_PANED_KEY);
383 /* We need to force a redraw here in order to get the right
384 position of the horizontal paned separator */
385 gtk_widget_show (GTK_WIDGET (self));
390 save_state (ModestWindow *window)
393 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
394 ModestMainWindowPrivate *priv;
396 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
397 conf = modest_runtime_get_conf ();
399 modest_widget_memory_save (conf,G_OBJECT(self),
400 MODEST_CONF_MAIN_WINDOW_KEY);
401 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
402 MODEST_CONF_MAIN_PANED_KEY);
403 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
404 // MODEST_CONF_HEADER_VIEW_KEY);
405 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
406 MODEST_CONF_FOLDER_VIEW_KEY);
410 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
412 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
413 gtk_scrolled_window_add_with_viewport
414 (GTK_SCROLLED_WINDOW(win), widget);
416 gtk_container_add (GTK_CONTAINER(win),
422 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMainWindow *self)
424 modest_window_save_state (MODEST_WINDOW(self));
430 on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self)
432 /* When going online, do the equivalent of pressing the send/receive button,
433 * as per the specification:
434 * (without the check for >0 accounts, though that is not specified): */
436 TnyDevice *device = tny_account_store_get_device (store);
438 /* Check that we are really online.
439 * This signal should not be emitted when we are not connected,
440 * but it seems to happen sometimes: */
441 if (!tny_device_is_online (device))
444 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
445 printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id);
447 /* Stop the existing send queues: */
448 modest_runtime_remove_all_send_queues ();
450 /* Create the send queues again, using the appropriate transport accounts
451 * for this new connection.
452 * This could be the first time that they are created if this is the first
454 /* TODO: Does this really destroy the TnySendQueues and their threads
455 * We do not want 2 TnySendQueues to exist with the same underlying
456 * outbox directory. */
457 GSList *account_names = modest_account_mgr_account_names (
458 modest_runtime_get_account_mgr(),
459 TRUE /* enabled accounts only */);
460 GSList *iter = account_names;
462 const gchar *account_name = (const gchar*)(iter->data);
464 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (
465 modest_tny_account_store_get_transport_account_for_open_connection
466 (modest_runtime_get_account_store(), account_name));
468 printf ("debug: %s:\n Transport account for %s: %s\n", __FUNCTION__, account_name,
469 tny_account_get_id(TNY_ACCOUNT(account)));
470 modest_runtime_get_send_queue (account);
474 iter = g_slist_next (iter);
477 g_slist_free (account_names);
480 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self));
484 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
486 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
489 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
493 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
495 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
497 /* Update visibility */
500 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
504 connect_signals (ModestMainWindow *self)
506 ModestWindowPrivate *parent_priv;
507 ModestMainWindowPrivate *priv;
510 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
511 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
514 g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
515 G_CALLBACK(on_inner_widgets_key_pressed), self);
516 g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
517 G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
518 g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
519 G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
521 /* Folder view CSM */
522 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
523 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
524 g_signal_connect (G_OBJECT(priv->folder_view), "tap-and-hold",
525 G_CALLBACK(_folder_view_csm_menu_activated),
528 g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
529 G_CALLBACK(modest_ui_actions_on_header_selected), self);
530 g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
531 G_CALLBACK(modest_ui_actions_on_header_activated), self);
532 g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
533 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
534 g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
535 G_CALLBACK(on_inner_widgets_key_pressed), self);
536 g_signal_connect (G_OBJECT(priv->header_view), "msg_count_changed",
537 G_CALLBACK(_on_msg_count_changed), self);
539 /* Header view CSM */
540 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
541 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
542 g_signal_connect (G_OBJECT(priv->header_view), "tap-and-hold",
543 G_CALLBACK(_header_view_csm_menu_activated),
547 g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
548 g_signal_connect (G_OBJECT (self), "window-state-event",
549 G_CALLBACK (modest_main_window_window_state_event),
551 g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
553 /* Mail Operation Queue */
554 priv->queue_changed_handler_uid =
555 g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
556 "queue-changed", G_CALLBACK (on_queue_changed), self);
558 /* Track changes in the device name */
559 g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
560 "key_changed", G_CALLBACK (on_configuration_key_changed),
563 /* Track account changes. We need to refresh the toolbar */
564 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
565 "account_update", G_CALLBACK (on_account_update),
569 g_signal_connect (G_OBJECT (modest_runtime_get_account_store()),
570 "password_requested",
571 G_CALLBACK (modest_ui_actions_on_password_requested), self);
574 g_signal_connect (G_OBJECT(modest_runtime_get_account_store()),
575 "connecting-finished",
576 G_CALLBACK(on_account_store_connecting_finished), self);
580 /** Idle handler, to send/receive at startup .*/
582 sync_accounts_cb (ModestMainWindow *win)
584 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
585 return FALSE; /* Do not call this idle handler again. */
589 static void on_hildon_program_is_topmost_notify(GObject *self,
590 GParamSpec *propert_param, gpointer user_data)
592 HildonProgram *app = HILDON_PROGRAM (self);
595 ModestWindow* self = MODEST_WINDOW(user_data);
598 /* Note that use of hildon_program_set_can_hibernate()
599 * is generally referred to as "setting the killable flag",
600 * though hibernation does not seem equal to death.
603 if (hildon_program_get_is_topmost (app)) {
604 /* Prevent hibernation when the progam comes to the foreground,
605 * because hibernation should only happen when the application
606 * is in the background: */
607 hildon_program_set_can_hibernate (app, FALSE);
609 /* Allow hibernation if the program has gone to the background: */
611 /* However, prevent hibernation while the settings are being changed: */
612 const gboolean hibernation_prevented =
613 modest_window_mgr_get_hibernation_is_prevented (
614 modest_runtime_get_window_mgr ());
616 if (hibernation_prevented)
617 hildon_program_set_can_hibernate (app, FALSE);
619 /* Allow hibernation, after saving the state: */
620 modest_osso_save_state();
621 hildon_program_set_can_hibernate (app, TRUE);
628 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
630 GtkWidget *folder_win = (GtkWidget *) user_data;
631 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
633 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
634 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
635 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
637 gtk_widget_show (GTK_WIDGET (priv->folder_view));
639 /* Connect signals */
640 connect_signals ((ModestMainWindow*)self);
642 /* Set account store */
643 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
644 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
646 /* Load previous osso state, for instance if we are being restored from
648 modest_osso_load_state ();
650 /* Restore window & widget settings */
652 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
654 /* Check if accounts exist and show the account wizard if not */
655 gboolean accounts_exist =
656 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
658 if (!accounts_exist) {
659 /* This is necessary to have the main window shown behind the dialog
660 It's an ugly hack... jschmid */
661 gtk_widget_show_all(GTK_WIDGET(self));
662 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
668 /* on_window_destroy (ModestWindow *window, */
669 /* ModestWindowMgr *self) */
671 /* ModestMainWindow *mw = NULL; */
672 /* ModestMainWindowPrivate *priv = NULL; */
674 /* mw = MODEST_MAIN_WINDOW (window); */
675 /* priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self); */
677 /* g_print ("\tMW: %d\n", ((GObject*)mw)->ref_count); */
678 /* g_print ("\tHV: %d\n", ((GObject*)priv->header_view)->ref_count); */
679 /* g_print ("\tFV: %d\n", ((GObject*)priv->folder_view)->ref_count); */
683 modest_main_window_new (void)
685 ModestMainWindow *self = NULL;
686 ModestMainWindowPrivate *priv = NULL;
687 ModestWindowPrivate *parent_priv = NULL;
688 GtkWidget *folder_win = NULL;
689 ModestDimmingRulesGroup *menu_rules_group = NULL;
690 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
691 GtkActionGroup *action_group = NULL;
692 GError *error = NULL;
693 GdkPixbuf *window_icon = NULL;
694 ModestConf *conf = NULL;
695 GtkAction *action = NULL;
697 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
698 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
699 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
701 parent_priv->ui_manager = gtk_ui_manager_new();
702 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
704 action_group = gtk_action_group_new ("ModestMainWindowActions");
705 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
706 gtk_action_group_set_translate_func (action_group, (GtkTranslateFunc) translate_func, GETTEXT_PACKAGE, g_free);
708 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules");
709 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules");
711 /* Add common actions */
712 gtk_action_group_add_actions (action_group,
713 modest_action_entries,
714 G_N_ELEMENTS (modest_action_entries),
717 gtk_action_group_add_actions (action_group,
718 modest_folder_view_action_entries,
719 G_N_ELEMENTS (modest_folder_view_action_entries),
722 gtk_action_group_add_actions (action_group,
723 modest_header_view_action_entries,
724 G_N_ELEMENTS (modest_header_view_action_entries),
727 gtk_action_group_add_toggle_actions (action_group,
728 modest_toggle_action_entries,
729 G_N_ELEMENTS (modest_toggle_action_entries),
732 gtk_action_group_add_toggle_actions (action_group,
733 modest_main_window_toggle_action_entries,
734 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
737 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
738 g_object_unref (action_group);
740 /* Load the UI definition */
741 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
742 MODEST_UIDIR "modest-main-window-ui.xml", &error);
744 g_warning ("Could not merge modest-ui.xml: %s", error->message);
745 g_error_free (error);
749 /* Add common dimming rules */
750 modest_dimming_rules_group_add_rules (menu_rules_group,
751 modest_main_window_menu_dimming_entries,
752 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
754 modest_dimming_rules_group_add_rules (toolbar_rules_group,
755 modest_main_window_toolbar_dimming_entries,
756 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
759 /* Insert dimming rules group for this window */
760 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
761 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
762 g_object_unref (menu_rules_group);
763 g_object_unref (toolbar_rules_group);
765 /* Add accelerators */
766 gtk_window_add_accel_group (GTK_WINDOW (self),
767 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
769 /* Menubar. Update the state of some toggles */
770 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
771 conf = modest_runtime_get_conf ();
772 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
773 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
774 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
775 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
776 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
777 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
778 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
779 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
780 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
782 /* Get device name */
783 modest_maemo_utils_get_device_name ();
787 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
788 if (!priv->header_view)
789 g_printerr ("modest: cannot instantiate header view\n");
790 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
791 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
792 MODEST_CONF_HEADER_VIEW_KEY);
795 priv->empty_view = create_empty_view ();
797 /* Create scrolled windows */
798 folder_win = gtk_scrolled_window_new (NULL, NULL);
799 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
800 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
802 GTK_POLICY_AUTOMATIC);
803 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
805 GTK_POLICY_AUTOMATIC);
808 priv->main_paned = gtk_hpaned_new ();
809 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
810 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
811 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
813 /* putting it all together... */
814 priv->main_vbox = gtk_vbox_new (FALSE, 6);
815 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
817 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
819 /* Set window icon */
820 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
821 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
823 HildonProgram *app = hildon_program_get_instance ();
824 hildon_program_add_window (app, HILDON_WINDOW (self));
826 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
827 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
829 g_signal_connect (G_OBJECT(self), "show",
830 G_CALLBACK (modest_main_window_on_show), folder_win);
833 restore_settings (MODEST_MAIN_WINDOW(self), FALSE);
836 /* g_signal_connect (self, "destroy", */
837 /* G_CALLBACK (on_window_destroy), self); */
840 return MODEST_WINDOW(self);
844 modest_main_window_close_all (ModestMainWindow *self)
847 GtkResponseType response;
849 /* Create the confirmation dialog MSG-NOT308 */
850 note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
851 _("emev_nc_close_windows"),
852 _("mcen_bd_yes"), GTK_RESPONSE_YES,
853 _("mcen_bd_no"), GTK_RESPONSE_NO,
856 response = gtk_dialog_run (GTK_DIALOG (note));
857 gtk_widget_destroy (GTK_WIDGET (note));
859 if (response == GTK_RESPONSE_YES)
867 modest_main_window_set_style (ModestMainWindow *self,
868 ModestMainWindowStyle style)
870 ModestMainWindowPrivate *priv;
871 ModestWindowPrivate *parent_priv;
874 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
876 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
877 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
879 /* no change -> nothing to do */
880 if (priv->style == style)
883 /* Get toggle button */
884 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
888 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
889 /* Remove main paned */
890 g_object_ref (priv->main_paned);
891 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
893 /* Reparent the contents widget to the main vbox */
894 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
896 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
897 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
898 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
901 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
902 /* Remove header view */
903 g_object_ref (priv->contents_widget);
904 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
906 /* Reparent the main paned */
907 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
908 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
910 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
911 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
912 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
916 g_return_if_reached ();
919 /* Let header view grab the focus if it's being shown */
920 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
921 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
923 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
926 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
929 ModestMainWindowStyle
930 modest_main_window_get_style (ModestMainWindow *self)
932 ModestMainWindowPrivate *priv;
934 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
936 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
943 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
945 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
946 ModestWindowPrivate *parent_priv;
947 ModestWindowMgr *mgr;
948 gboolean is_fullscreen;
949 GtkAction *fs_toggle_action;
952 mgr = modest_runtime_get_window_mgr ();
954 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
956 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
958 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
959 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
960 if (is_fullscreen != active) {
961 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
970 set_homogeneous (GtkWidget *widget,
973 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
974 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
978 modest_main_window_show_toolbar (ModestWindow *self,
979 gboolean show_toolbar)
981 ModestMainWindowPrivate *priv = NULL;
982 ModestWindowPrivate *parent_priv = NULL;
983 GtkWidget *reply_button = NULL, *menu = NULL;
984 GtkWidget *placeholder = NULL;
987 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
988 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
989 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
991 /* Set optimized view status */
992 priv->optimized_view = !show_toolbar;
994 if (!parent_priv->toolbar) {
995 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
998 /* Set homogeneous toolbar */
999 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1000 set_homogeneous, NULL);
1002 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1003 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1004 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1005 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1006 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1007 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1008 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1009 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1011 /* Add ProgressBar (Transfer toolbar) */
1012 priv->progress_bar = modest_progress_bar_widget_new ();
1013 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1014 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1015 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1016 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1017 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1019 /* Connect cancel 'clicked' signal to abort progress mode */
1020 g_signal_connect(priv->cancel_toolitem, "clicked",
1021 G_CALLBACK(cancel_progressbar),
1024 /* Add it to the observers list */
1025 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1028 hildon_window_add_toolbar (HILDON_WINDOW (self),
1029 GTK_TOOLBAR (parent_priv->toolbar));
1031 /* Set reply button tap and hold menu */
1032 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1033 "/ToolBar/ToolbarMessageReply");
1034 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1035 "/ToolbarReplyCSM");
1036 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1038 /* Set send & receive button tap and hold menu */
1039 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1044 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1045 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1046 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1048 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1049 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1051 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1056 compare_display_names (ModestAccountData *a,
1057 ModestAccountData *b)
1059 return strcmp (a->display_name, b->display_name);
1063 on_account_update (TnyAccountStore *account_store,
1064 const gchar *account_name,
1067 GSList *account_names, *iter, *accounts;
1068 ModestMainWindow *self;
1069 ModestMainWindowPrivate *priv;
1070 ModestWindowPrivate *parent_priv;
1071 ModestAccountMgr *mgr;
1072 gint i, num_accounts;
1073 GtkActionGroup *action_group;
1075 gchar *default_account;
1076 GtkWidget *send_receive_button, *item;
1078 self = MODEST_MAIN_WINDOW (user_data);
1079 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1080 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1082 /* Get enabled account IDs */
1083 mgr = modest_runtime_get_account_mgr ();
1084 account_names = modest_account_mgr_account_names (mgr, TRUE);
1085 iter = account_names;
1089 ModestAccountData *account_data =
1090 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
1091 accounts = g_slist_prepend (accounts, account_data);
1095 g_slist_free (account_names);
1097 /* Order the list of accounts by its display name */
1098 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1099 num_accounts = g_slist_length (accounts);
1101 /* Delete old send&receive popup items. We can not just do a
1102 menu_detach because it does not work well with
1104 if (priv->accounts_popup)
1105 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
1106 (GtkCallback) gtk_widget_destroy, NULL);
1108 /* Delete old entries in the View menu. Do not free groups, it
1110 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1112 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1113 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1114 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
1115 GTK_ACTION_GROUP (groups->data));
1118 if (priv->merge_ids) {
1119 for (i = 0; i < priv->merge_ids->len; i++)
1120 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1121 g_byte_array_free (priv->merge_ids, TRUE);
1123 /* We need to call this in order to ensure
1124 that the new actions are added in the right
1125 order (alphabetical */
1126 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1128 groups = g_list_next (groups);
1130 priv->merge_ids = g_byte_array_sized_new (num_accounts);
1132 /* Get send receive button */
1133 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1134 "/ToolBar/ToolbarSendReceive");
1136 /* Create the menu */
1137 if (num_accounts > 1) {
1138 if (!priv->accounts_popup)
1139 priv->accounts_popup = gtk_menu_new ();
1140 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1141 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1142 g_signal_connect (G_OBJECT (item),
1144 G_CALLBACK (on_send_receive_csm_activated),
1146 item = gtk_separator_menu_item_new ();
1147 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1150 /* Create a new action group */
1151 default_account = modest_account_mgr_get_default_account (mgr);
1152 action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1153 for (i = 0; i < num_accounts; i++) {
1154 gchar *display_name = NULL;
1156 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1158 /* Create display name. The default account is shown differently */
1159 if (default_account && account_data->account_name &&
1160 !(strcmp (default_account, account_data->account_name) == 0)) {
1161 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
1162 account_data->display_name);
1165 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
1166 account_data->display_name);
1169 /* Create action and add it to the action group. The
1170 action name must be the account name, this way we
1171 could know in the handlers the account to show */
1172 if(account_data->account_name) {
1173 gchar* item_name, *refresh_action_name;
1175 GtkAction *view_account_action, *refresh_account_action;
1177 view_account_action = gtk_action_new (account_data->account_name,
1178 display_name, NULL, NULL);
1179 gtk_action_group_add_action (action_group, view_account_action);
1181 /* Add ui from account data. We allow 2^9-1 account
1182 changes in a single execution because we're
1183 downcasting the guint to a guint8 in order to use a
1184 GByteArray, it should be enough */
1185 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1186 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1187 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1188 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1190 "/MenuBar/ViewMenu/ViewMenuAdditions",
1192 account_data->account_name,
1193 GTK_UI_MANAGER_MENUITEM,
1196 /* Connect the action signal "activate" */
1197 g_signal_connect (G_OBJECT (view_account_action),
1199 G_CALLBACK (on_show_account_action_activated),
1202 /* Create the items for the Tools->Send&Receive submenu */
1203 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1204 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
1205 display_name, NULL, NULL);
1206 gtk_action_group_add_action (action_group, refresh_account_action);
1208 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1209 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1210 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1212 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1214 refresh_action_name,
1215 GTK_UI_MANAGER_MENUITEM,
1217 g_free (refresh_action_name);
1219 g_signal_connect_data (G_OBJECT (refresh_account_action),
1221 G_CALLBACK (on_refresh_account_action_activated),
1222 g_strdup (account_data->account_name),
1223 (GClosureNotify) g_free,
1226 /* Create item and add it to the send&receive
1227 CSM. If there is only one account then
1229 if (priv->accounts_popup) {
1230 item = gtk_menu_item_new_with_label (display_name);
1231 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1232 g_signal_connect_data (G_OBJECT (item),
1234 G_CALLBACK (on_send_receive_csm_activated),
1235 g_strdup (account_data->account_name),
1236 (GClosureNotify) g_free,
1243 g_free (display_name);
1244 modest_account_mgr_free_account_data (mgr, account_data);
1246 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1248 if (priv->accounts_popup) {
1249 /* Mandatory in order to view the menu contents */
1250 gtk_widget_show_all (priv->accounts_popup);
1252 /* Setup tap_and_hold just if was not done before*/
1253 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1254 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1258 g_slist_free (accounts);
1259 g_free (default_account);
1263 * This function manages the key events used to navigate between
1264 * header and folder views (when the window is in split view)
1267 * -------------------------------------------------
1268 * HeaderView GDK_Left Move focus to folder view
1269 * FolderView GDK_Right Move focus to header view
1271 * There is no need to scroll to selected row, the widgets will be the
1272 * responsibles of doing that (probably managing the focus-in event
1275 on_inner_widgets_key_pressed (GtkWidget *widget,
1279 ModestMainWindowPrivate *priv;
1281 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1283 /* Do nothing if we're in SIMPLE style */
1284 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1287 if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1288 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1289 else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1290 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1296 set_alignment (GtkWidget *widget,
1299 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1300 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1304 create_empty_view (void)
1306 GtkLabel *label = NULL;
1307 GtkWidget *align = NULL;
1309 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1310 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1311 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1312 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1314 return GTK_WIDGET(align);
1318 create_details_widget (TnyAccount *account)
1323 vbox = gtk_vbox_new (FALSE, 0);
1325 /* Account description: */
1327 if (modest_tny_account_is_virtual_local_folders (account)) {
1328 /* Local folders: */
1330 /* Get device name */
1331 gchar *device_name = modest_conf_get_string (modest_runtime_get_conf(),
1332 MODEST_CONF_DEVICE_NAME, NULL);
1334 label = g_strdup_printf (_("mcen_fi_localroot_description"),
1336 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1337 g_free (device_name);
1340 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1341 gtk_box_pack_start (GTK_BOX (vbox),
1342 gtk_label_new (tny_account_get_name (account)),
1345 /* Other accounts, such as IMAP and POP: */
1350 /* Put proto in uppercase */
1351 proto = g_string_new (tny_account_get_proto (account));
1352 proto = g_string_ascii_up (proto);
1354 /* note: mcen_fi_localroot_description is something like "%s account"
1355 * however, we should display "%s account: %s"... therefore, ugly tmp */
1356 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1357 label = g_strdup_printf ("%s: %s", tmp,tny_account_get_name (account));
1360 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1361 g_string_free (proto, TRUE);
1367 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1368 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"),
1369 modest_tny_folder_store_get_message_count (folder_store));
1370 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1374 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"),
1375 modest_tny_folder_store_get_folder_count (folder_store));
1376 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1380 if (modest_tny_account_is_virtual_local_folders (account)) {
1381 /* FIXME: format size */
1382 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"),
1383 modest_tny_folder_store_get_local_size (folder_store));
1384 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1386 } else if (TNY_IS_ACCOUNT(folder_store)) {
1387 TnyAccount *account = TNY_ACCOUNT(folder_store);
1389 time_t last_updated;
1390 gchar *last_updated_string;
1391 /* Get last updated from configuration */
1392 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (),
1393 tny_account_get_id (account),
1394 MODEST_ACCOUNT_LAST_UPDATED,
1396 if (last_updated > 0)
1397 last_updated_string = modest_text_utils_get_display_date(last_updated);
1399 last_updated_string = g_strdup (_("mcen_va_never"));
1401 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
1402 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1403 g_free (last_updated_string);
1408 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1414 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1416 GtkAction *action = NULL;
1417 GtkWidget *widget = NULL;
1419 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1421 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1422 gtk_action_set_sensitive (action, FALSE);
1423 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1424 /* gtk_action_set_sensitive (action, FALSE); */
1425 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1426 gtk_widget_set_sensitive (widget, FALSE);
1430 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1432 GtkAction *action = NULL;
1433 GtkWidget *widget = NULL;
1435 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1437 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1438 gtk_action_set_sensitive (action, TRUE);
1439 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1440 /* gtk_action_set_sensitive (action, TRUE); */
1441 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1442 gtk_widget_set_sensitive (widget, TRUE);
1447 _on_msg_count_changed (ModestHeaderView *header_view,
1449 TnyFolderChange *change,
1450 ModestMainWindow *main_window)
1452 printf ("DEBUG: %s\n", __FUNCTION__);
1453 gboolean folder_empty = FALSE;
1454 TnyFolderChangeChanged changed;
1456 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1457 g_return_if_fail (TNY_IS_FOLDER(folder));
1458 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1460 changed = tny_folder_change_get_changed (change);
1462 /* If something changes */
1463 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1464 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1466 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1468 printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1470 /* Set contents style of headers view */
1472 modest_main_window_set_contents_style (main_window,
1473 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1476 modest_main_window_set_contents_style (main_window,
1477 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1483 modest_main_window_set_contents_style (ModestMainWindow *self,
1484 ModestMainWindowContentsStyle style)
1486 ModestMainWindowPrivate *priv;
1488 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1490 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1492 /* We allow to set the same content style than the previously
1493 set if there are details, because it could happen when we're
1494 selecting different accounts consecutively */
1495 if ((priv->contents_style == style) &&
1496 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1499 /* Remove previous child. Delete it if it was an account
1501 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1503 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1504 g_object_ref (content);
1505 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1506 g_object_ref (priv->empty_view);
1507 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1510 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1513 priv->contents_style = style;
1515 switch (priv->contents_style) {
1516 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1517 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1519 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1521 TnyFolderStore *selected_folderstore =
1522 modest_folder_view_get_selected (priv->folder_view);
1523 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1524 priv->details_widget = create_details_widget (
1525 TNY_ACCOUNT (selected_folderstore));
1527 wrap_in_scrolled_window (priv->contents_widget,
1528 priv->details_widget);
1530 g_object_unref (selected_folderstore);
1533 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1534 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1537 g_return_if_reached ();
1541 gtk_widget_show_all (priv->contents_widget);
1544 ModestMainWindowContentsStyle
1545 modest_main_window_get_contents_style (ModestMainWindow *self)
1547 ModestMainWindowPrivate *priv;
1549 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1551 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1552 return priv->contents_style;
1557 on_configuration_key_changed (ModestConf* conf,
1559 ModestConfEvent event,
1560 ModestMainWindow *self)
1562 ModestMainWindowPrivate *priv;
1563 TnyAccount *account;
1565 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1568 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1570 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1573 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1574 if (TNY_IS_ACCOUNT (account) &&
1575 !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1578 const gchar *device_name;
1582 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1583 label = GTK_LABEL (children->data);
1585 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1586 MODEST_CONF_DEVICE_NAME, NULL);
1588 new_text = g_strdup_printf ("%s: %s",
1589 _("mcen_fi_localroot_description"),
1592 gtk_label_set_text (label, new_text);
1593 gtk_widget_show (GTK_WIDGET (label));
1596 g_list_free (children);
1598 g_object_unref (account);
1602 set_toolbar_transfer_mode (ModestMainWindow *self)
1604 ModestMainWindowPrivate *priv = NULL;
1606 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1608 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1610 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1612 if (priv->progress_bar_timeout > 0) {
1613 g_source_remove (priv->progress_bar_timeout);
1614 priv->progress_bar_timeout = 0;
1621 set_toolbar_mode (ModestMainWindow *self,
1622 ModestToolBarModes mode)
1624 ModestWindowPrivate *parent_priv = NULL;
1625 ModestMainWindowPrivate *priv = NULL;
1626 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1628 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1630 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1631 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1633 /* In case this was called before the toolbar exists: */
1634 if (!(parent_priv->toolbar))
1637 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1639 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1640 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1641 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1643 /* Sets current toolbar mode */
1644 priv->current_toolbar_mode = mode;
1646 /* Show and hide toolbar items */
1648 case TOOLBAR_MODE_NORMAL:
1650 gtk_action_set_visible (sort_action, TRUE);
1652 gtk_action_set_visible (refresh_action, TRUE);
1653 if (priv->progress_toolitem) {
1654 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1655 gtk_widget_hide (priv->progress_toolitem);
1657 if (priv->progress_bar)
1658 gtk_widget_hide (priv->progress_bar);
1661 gtk_action_set_visible (cancel_action, FALSE);
1663 /* Hide toolbar if optimized view is enabled */
1664 if (priv->optimized_view)
1665 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1667 case TOOLBAR_MODE_TRANSFER:
1669 gtk_action_set_visible (sort_action, FALSE);
1671 gtk_action_set_visible (refresh_action, FALSE);
1673 gtk_action_set_visible (cancel_action, TRUE);
1674 if (priv->progress_toolitem) {
1675 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1676 gtk_widget_show (priv->progress_toolitem);
1678 if (priv->progress_bar)
1679 gtk_widget_show (priv->progress_bar);
1681 /* Show toolbar if it's hiden (optimized view ) */
1682 if (priv->optimized_view)
1683 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1686 g_return_if_reached ();
1691 cancel_progressbar (GtkToolButton *toolbutton,
1692 ModestMainWindow *self)
1695 ModestMainWindowPrivate *priv;
1697 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1699 /* Get operation observers and cancel its current operation */
1700 tmp = priv->progress_widgets;
1702 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1703 tmp=g_slist_next(tmp);
1708 observers_empty (ModestMainWindow *self)
1711 ModestMainWindowPrivate *priv;
1712 gboolean is_empty = TRUE;
1713 guint pending_ops = 0;
1715 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1716 tmp = priv->progress_widgets;
1718 /* Check all observers */
1719 while (tmp && is_empty) {
1720 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1721 is_empty = pending_ops == 0;
1723 tmp = g_slist_next(tmp);
1730 on_queue_changed (ModestMailOperationQueue *queue,
1731 ModestMailOperation *mail_op,
1732 ModestMailOperationQueueNotification type,
1733 ModestMainWindow *self)
1735 ModestMainWindowPrivate *priv;
1736 ModestMailOperationTypeOperation op_type;
1737 ModestToolBarModes mode;
1739 gboolean mode_changed = FALSE;
1740 /* ModestMailOperationStatus status; */
1742 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1743 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1745 /* Get toolbar mode from operation id*/
1746 op_type = modest_mail_operation_get_type_operation (mail_op);
1748 case MODEST_MAIL_OPERATION_TYPE_SEND:
1749 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1750 mode = TOOLBAR_MODE_TRANSFER;
1751 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1752 mode_changed = TRUE;
1755 mode = TOOLBAR_MODE_NORMAL;
1760 /* Add operation observers and change toolbar if neccessary*/
1761 tmp = priv->progress_widgets;
1763 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1764 if (mode == TOOLBAR_MODE_TRANSFER) {
1766 set_toolbar_transfer_mode(self);
1768 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1770 tmp = g_slist_next (tmp);
1774 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1775 /* Change toolbar mode */
1776 if (mode == TOOLBAR_MODE_TRANSFER) {
1778 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1780 tmp = g_slist_next (tmp);
1783 /* If no more operations are being observed, NORMAL mode is enabled again */
1784 if (observers_empty (self)) {
1785 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1796 on_show_account_action_activated (GtkAction *action,
1799 ModestAccountData *acc_data;
1800 ModestMainWindow *self;
1801 ModestMainWindowPrivate *priv;
1802 ModestAccountMgr *mgr;
1803 const gchar *acc_name;
1805 self = MODEST_MAIN_WINDOW (user_data);
1806 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1808 /* Get account data */
1809 acc_name = gtk_action_get_name (action);
1810 mgr = modest_runtime_get_account_mgr ();
1811 acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1813 /* Set the new visible & active account */
1814 if (acc_data->store_account) {
1815 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1816 acc_data->store_account->account_name);
1817 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1821 modest_account_mgr_free_account_data (mgr, acc_data);
1825 refresh_account (const gchar *account_name)
1829 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1831 /* If account_name == NULL, we must update all (option All) */
1833 modest_ui_actions_do_send_receive_all (win);
1835 modest_ui_actions_do_send_receive (account_name, win);
1839 on_refresh_account_action_activated (GtkAction *action,
1842 refresh_account ((const gchar*) user_data);
1846 on_send_receive_csm_activated (GtkMenuItem *item,
1849 refresh_account ((const gchar*) user_data);
1853 translate_func (const gchar *msgid,
1854 const gchar *domain_name)