1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-maemo-utils.h>
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-mail-operation.h"
60 #include "modest-icon-names.h"
61 #include "modest-progress-bar-widget.h"
62 #include "modest-text-utils.h"
63 #include "modest-ui-dimming-manager.h"
64 #include "maemo/modest-osso-state-saving.h"
65 #include "modest-text-utils.h"
66 #include "modest-signal-mgr.h"
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-program.h>
71 #include <hildon/hildon-program.h>
72 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
74 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
81 /* 'private'/'protected' functions */
82 static void modest_main_window_class_init (ModestMainWindowClass *klass);
83 static void modest_main_window_init (ModestMainWindow *obj);
84 static void modest_main_window_finalize (GObject *obj);
86 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
87 GdkEventWindowState *event,
90 static void connect_signals (ModestMainWindow *self);
92 static void modest_main_window_disconnect_signals (ModestWindow *self);
94 static void restore_settings (ModestMainWindow *self,
95 gboolean do_folder_view_too);
97 static void save_state (ModestWindow *self);
99 static void modest_main_window_show_toolbar (ModestWindow *window,
100 gboolean show_toolbar);
102 static void cancel_progressbar (GtkToolButton *toolbutton,
103 ModestMainWindow *self);
105 static void on_queue_changed (ModestMailOperationQueue *queue,
106 ModestMailOperation *mail_op,
107 ModestMailOperationQueueNotification type,
108 ModestMainWindow *self);
110 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
112 static void account_number_changed (TnyAccountStore *account_store,
113 /* const gchar *account_name, */
117 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
121 static void on_configuration_key_changed (ModestConf* conf,
123 ModestConfEvent event,
124 ModestConfNotificationId id,
125 ModestMainWindow *self);
127 static void set_toolbar_mode (ModestMainWindow *self,
128 ModestToolBarModes mode);
130 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
132 static void on_show_account_action_activated (GtkAction *action,
135 static void on_refresh_account_action_activated (GtkAction *action,
138 static void on_send_receive_csm_activated (GtkMenuItem *item,
142 _on_msg_count_changed (ModestHeaderView *header_view,
144 TnyFolderChange *change,
145 ModestMainWindow *main_window);
148 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
151 static GtkWidget * create_empty_view (void);
154 on_folder_view_focus_in (GtkWidget *widget,
155 GdkEventFocus *event,
158 on_header_view_focus_in (GtkWidget *widget,
159 GdkEventFocus *event,
162 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
163 TnyFolderStore *folder_store,
165 ModestMainWindow *main_window);
168 set_at_least_one_account_visible(ModestMainWindow *self);
171 /* list my signals */
178 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
179 struct _ModestMainWindowPrivate {
180 GtkWidget *msg_paned;
181 GtkWidget *main_paned;
182 GtkWidget *main_vbox;
183 GtkWidget *contents_widget;
184 GtkWidget *empty_view;
186 /* Progress observers */
187 GtkWidget *progress_bar;
188 GSList *progress_widgets;
191 GtkWidget *progress_toolitem;
192 GtkWidget *cancel_toolitem;
193 GtkWidget *sort_toolitem;
194 GtkWidget *refresh_toolitem;
195 ModestToolBarModes current_toolbar_mode;
197 /* Merge ids used to add/remove accounts to the ViewMenu*/
198 GByteArray *merge_ids;
200 /* On-demand widgets */
201 GtkWidget *accounts_popup;
202 GtkWidget *details_widget;
204 /* Optimized view enabled */
205 gboolean optimized_view;
207 /* Optimized view enabled */
208 gboolean send_receive_in_progress;
210 ModestHeaderView *header_view;
211 ModestFolderView *folder_view;
213 ModestMainWindowStyle style;
214 ModestMainWindowContentsStyle contents_style;
216 guint progress_bar_timeout;
218 /* Signal handler UIDs */
219 GList *queue_err_signals;
222 ModestConfNotificationId notification_id;
224 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
225 MODEST_TYPE_MAIN_WINDOW, \
226 ModestMainWindowPrivate))
228 typedef struct _GetMsgAsyncHelper {
229 ModestMainWindowPrivate *main_window_private;
231 ModestTnyMsgReplyType reply_type;
232 ModestTnyMsgForwardType forward_type;
239 static GtkWindowClass *parent_class = NULL;
242 /* Private actions */
243 /* This is the context sensitive menu: */
244 static const GtkActionEntry modest_folder_view_action_entries [] = {
246 /* Folder View CSM actions */
247 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
248 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
249 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
250 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
251 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
252 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
255 static const GtkActionEntry modest_header_view_action_entries [] = {
257 /* Header View CSM actions */
258 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
259 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
260 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
261 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
262 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
263 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
264 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
265 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
266 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
267 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
270 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
271 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
274 /************************************************************************/
277 modest_main_window_get_type (void)
279 static GType my_type = 0;
281 static const GTypeInfo my_info = {
282 sizeof(ModestMainWindowClass),
283 NULL, /* base init */
284 NULL, /* base finalize */
285 (GClassInitFunc) modest_main_window_class_init,
286 NULL, /* class finalize */
287 NULL, /* class data */
288 sizeof(ModestMainWindow),
290 (GInstanceInitFunc) modest_main_window_init,
293 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
301 modest_main_window_class_init (ModestMainWindowClass *klass)
303 GObjectClass *gobject_class;
304 gobject_class = (GObjectClass*) klass;
305 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
307 parent_class = g_type_class_peek_parent (klass);
308 gobject_class->finalize = modest_main_window_finalize;
310 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
312 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
313 modest_window_class->save_state_func = save_state;
314 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
315 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
316 modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
320 modest_main_window_init (ModestMainWindow *obj)
322 ModestMainWindowPrivate *priv;
324 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
326 priv->queue_err_signals = NULL;
327 priv->msg_paned = NULL;
328 priv->main_paned = NULL;
329 priv->main_vbox = NULL;
330 priv->header_view = NULL;
331 priv->folder_view = NULL;
332 priv->contents_widget = NULL;
333 priv->accounts_popup = NULL;
334 priv->details_widget = NULL;
335 priv->empty_view = NULL;
336 priv->progress_widgets = NULL;
337 priv->progress_bar = NULL;
338 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
339 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
340 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
341 priv->merge_ids = NULL;
342 priv->optimized_view = FALSE;
343 priv->send_receive_in_progress = FALSE;
344 priv->progress_bar_timeout = 0;
345 priv->sighandlers = NULL;
349 modest_main_window_finalize (GObject *obj)
351 ModestMainWindowPrivate *priv;
353 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
355 if (priv->notification_id) {
356 modest_conf_forget_namespace (modest_runtime_get_conf (),
357 MODEST_CONF_NAMESPACE,
358 priv->notification_id);
361 /* Sanity check: shouldn't be needed, the window mgr should
362 call this function before */
363 modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
365 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
367 g_slist_free (priv->progress_widgets);
369 g_byte_array_free (priv->merge_ids, TRUE);
371 if (priv->progress_bar_timeout > 0) {
372 g_source_remove (priv->progress_bar_timeout);
373 priv->progress_bar_timeout = 0;
376 G_OBJECT_CLASS(parent_class)->finalize (obj);
380 modest_main_window_get_child_widget (ModestMainWindow *self,
381 ModestWidgetType widget_type)
383 ModestMainWindowPrivate *priv;
386 g_return_val_if_fail (self, NULL);
387 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
390 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
392 switch (widget_type) {
393 case MODEST_WIDGET_TYPE_HEADER_VIEW:
394 widget = (GtkWidget*)priv->header_view; break;
395 case MODEST_WIDGET_TYPE_FOLDER_VIEW:
396 widget = (GtkWidget*)priv->folder_view; break;
401 return widget ? GTK_WIDGET(widget) : NULL;
406 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
409 ModestMainWindowPrivate *priv;
411 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
413 conf = modest_runtime_get_conf ();
415 modest_widget_memory_restore (conf, G_OBJECT(self),
416 MODEST_CONF_MAIN_WINDOW_KEY);
418 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
419 MODEST_CONF_HEADER_VIEW_KEY);
421 if (do_folder_view_too)
422 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
423 MODEST_CONF_FOLDER_VIEW_KEY);
425 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
426 MODEST_CONF_MAIN_PANED_KEY);
428 /* We need to force a redraw here in order to get the right
429 position of the horizontal paned separator */
430 gtk_widget_show (GTK_WIDGET (self));
435 save_state (ModestWindow *window)
438 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
439 ModestMainWindowPrivate *priv;
441 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
442 conf = modest_runtime_get_conf ();
444 modest_widget_memory_save (conf,G_OBJECT(self),
445 MODEST_CONF_MAIN_WINDOW_KEY);
446 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
447 MODEST_CONF_MAIN_PANED_KEY);
448 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
449 // MODEST_CONF_HEADER_VIEW_KEY);
450 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
451 MODEST_CONF_FOLDER_VIEW_KEY);
455 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
457 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
458 gtk_scrolled_window_add_with_viewport
459 (GTK_SCROLLED_WINDOW(win), widget);
461 gtk_container_add (GTK_CONTAINER(win),
466 /* static gboolean */
467 /* on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMainWindow *self) */
469 /* modest_window_save_state (MODEST_WINDOW(self)); */
474 /* on_sendqueue_error_happened (TnySendQueue *self, TnyHeader *header, TnyMsg *msg, GError *err, ModestMainWindow *user_data) */
477 /* printf ("DEBUG: %s: err->code=%d, err->message=%s\n", __FUNCTION__, err->code, err->message); */
479 /* if (err->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL) */
480 /* /\* Don't show waste the user's time by showing him a dialog telling him */
481 /* * that he has just cancelled something: *\/ */
485 /* /\* Get the server name: *\/ */
486 /* const gchar* server_name = NULL; */
488 /* TnyCamelTransportAccount* server_account = tny_camel_send_queue_get_transport_account ( */
489 /* TNY_CAMEL_SEND_QUEUE (self)); */
490 /* if (server_account) { */
491 /* server_name = tny_account_get_hostname (TNY_ACCOUNT (server_account)); */
493 /* g_object_unref (server_account); */
494 /* server_account = NULL; */
497 /* if (!server_name) */
498 /* server_name = _("Unknown Server"); */
500 /* /\* Show the appropriate message text for the GError: *\/ */
501 /* gchar *message = NULL; */
503 /* switch (err->code) { */
504 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_HOST_LOOKUP_FAILED: */
505 /* message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name); */
507 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_SERVICE_UNAVAILABLE: */
508 /* message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name); */
510 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_AUTHENTICATION_NOT_SUPPORTED: */
511 /* /\* TODO: This logical ID seems more suitable for a wrong username or password than for a */
512 /* * wrong authentication method. The user is unlikely to guess at the real cause. */
514 /* message = g_strdup_printf (_("eemev_ni_ui_smtp_authentication_fail_error"), server_name); */
516 /* case TNY_TRANSPORT_ACCOUNT_ERROR_SEND: */
517 /* /\* TODO: Tinymail is still sending this sometimes when it should */
518 /* * send TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL. *\/ */
520 /* message = g_strdup (_("emev_ib_ui_smtp_send_error")); */
524 /* message = g_strdup (_("emev_ib_ui_smtp_send_error")); */
527 /* modest_maemo_show_information_note_and_forget (GTK_WINDOW (user_data), message); */
528 /* g_free (message); */
530 /* /\* TODO: Offer to remove the message, to avoid messages in future? *\/ */
532 /* TnyFolder *outbox = tny_send_queue_get_outbox (queue); */
533 /* tny_folder_remove_msg (outbox, header, NULL); */
534 /* tny_folder_sync (outbox, TRUE, NULL); */
535 /* g_object_unref (outbox); */
545 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
547 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
549 GList *oerrsignals = priv->queue_err_signals;
550 while (oerrsignals) {
551 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
552 g_signal_handler_disconnect (esignal->queue, esignal->signal);
553 g_slice_free (QueueErrorSignal, esignal);
554 oerrsignals = g_list_next (oerrsignals);
556 g_list_free (priv->queue_err_signals);
557 priv->queue_err_signals = NULL;
561 /* on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self) */
563 /* ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self); */
565 /* /\* When going online, do the equivalent of pressing the send/receive button, */
566 /* * as per the specification: */
567 /* * (without the check for >0 accounts, though that is not specified): *\/ */
569 /* TnyDevice *device = tny_account_store_get_device (store); */
571 /* /\* modest_folder_view_update_model (MODEST_FOLDER_VIEW (priv->folder_view), store); *\/ */
573 /* /\* Check that we are really online. */
574 /* * This signal should not be emitted when we are not connected, */
575 /* * but it seems to happen sometimes: *\/ */
576 /* if (!tny_device_is_online (device)) */
579 /* const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device)); */
580 /* printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id); */
582 /* /\* Stop the existing send queues: *\/ */
583 /* modest_runtime_remove_all_send_queues (); */
585 /* /\* Create the send queues again, using the appropriate transport accounts */
586 /* * for this new connection. */
587 /* * This could be the first time that they are created if this is the first */
588 /* * connection. *\/ */
589 /* /\* TODO: Does this really destroy the TnySendQueues and their threads */
590 /* * We do not want 2 TnySendQueues to exist with the same underlying */
591 /* * outbox directory. *\/ */
593 /* modest_main_window_cleanup_queue_error_signals (self); */
595 /* GSList *account_names = modest_account_mgr_account_names ( */
596 /* modest_runtime_get_account_mgr(), */
597 /* TRUE /\* enabled accounts only *\/); */
598 /* GSList *iter = account_names; */
600 /* const gchar *account_name = (const gchar*)(iter->data); */
601 /* if (account_name) { */
602 /* TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT ( */
603 /* modest_tny_account_store_get_transport_account_for_open_connection */
604 /* (modest_runtime_get_account_store(), account_name)); */
606 /* /\* Q: Is this the first location where the send-queues are requested? *\/ */
607 /* QueueErrorSignal *esignal = g_slice_new (QueueErrorSignal); */
608 /* printf ("debug: %s:\n Transport account for %s: %s\n", __FUNCTION__, account_name, */
609 /* tny_account_get_id(TNY_ACCOUNT(account))); */
610 /* esignal->queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (account)); */
611 /* esignal->signal = g_signal_connect (G_OBJECT (esignal->queue), "error-happened", */
612 /* G_CALLBACK (on_sendqueue_error_happened), self); */
613 /* priv->queue_err_signals = g_list_prepend (priv->queue_err_signals, esignal); */
617 /* iter = g_slist_next (iter); */
620 /* modest_account_mgr_free_account_names (account_names); */
621 /* account_names = NULL; */
623 /* modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self)); */
627 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
629 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
632 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
636 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
638 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
640 /* Update visibility */
643 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
647 modest_main_window_disconnect_signals (ModestWindow *self)
649 ModestMainWindowPrivate *priv;
650 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
652 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
653 priv->sighandlers = NULL;
657 connect_signals (ModestMainWindow *self)
659 ModestWindowPrivate *parent_priv;
660 ModestMainWindowPrivate *priv;
663 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
664 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
668 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
669 G_OBJECT(priv->folder_view), "key-press-event",
670 G_CALLBACK(on_inner_widgets_key_pressed), self);
671 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder_selection_changed",
672 G_CALLBACK(modest_main_window_on_folder_selection_changed), self);
673 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
674 G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
675 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event",
676 G_CALLBACK (on_folder_view_focus_in), self);
678 /* Folder view CSM */
679 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
680 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
681 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
682 G_CALLBACK(_folder_view_csm_menu_activated),
685 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
686 G_CALLBACK(modest_ui_actions_on_header_selected), self);
687 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
688 G_CALLBACK(modest_ui_actions_on_header_activated), self);
689 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
690 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
691 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
692 G_CALLBACK(on_inner_widgets_key_pressed), self);
693 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
694 G_CALLBACK(_on_msg_count_changed), self);
695 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
696 G_CALLBACK (on_header_view_focus_in), self);
698 /* Header view CSM */
699 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
700 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
701 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
702 G_CALLBACK(_header_view_csm_menu_activated),
706 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
707 G_CALLBACK (modest_main_window_window_state_event),
710 /* Mail Operation Queue */
711 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_mail_operation_queue ()),
712 "queue-changed", G_CALLBACK (on_queue_changed), self);
714 /* Track changes in the device name */
715 priv->notification_id = modest_conf_listen_to_namespace (modest_runtime_get_conf (),
716 MODEST_CONF_NAMESPACE);
717 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(modest_runtime_get_conf ()),
718 "key_changed", G_CALLBACK (on_configuration_key_changed),
721 /* Track account changes. We need to refresh the toolbar */
722 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store ()),
723 "account_inserted", G_CALLBACK (account_number_changed),
725 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store ()),
726 "account_removed", G_CALLBACK (account_number_changed),
729 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (modest_runtime_get_account_store()),
730 "password_requested",
731 G_CALLBACK (modest_ui_actions_on_password_requested), self);
735 /** Idle handler, to send/receive at startup .*/
737 sync_accounts_cb (ModestMainWindow *win)
739 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
740 return FALSE; /* Do not call this idle handler again. */
744 static void on_hildon_program_is_topmost_notify(GObject *self,
745 GParamSpec *propert_param, gpointer user_data)
747 HildonProgram *app = HILDON_PROGRAM (self);
750 ModestWindow* self = MODEST_WINDOW(user_data);
753 /* Note that use of hildon_program_set_can_hibernate()
754 * is generally referred to as "setting the killable flag",
755 * though hibernation does not seem equal to death.
758 if (hildon_program_get_is_topmost (app)) {
759 /* Prevent hibernation when the progam comes to the foreground,
760 * because hibernation should only happen when the application
761 * is in the background: */
762 hildon_program_set_can_hibernate (app, FALSE);
764 /* Allow hibernation if the program has gone to the background: */
766 /* However, prevent hibernation while the settings are being changed: */
767 const gboolean hibernation_prevented =
768 modest_window_mgr_get_hibernation_is_prevented (
769 modest_runtime_get_window_mgr ());
771 if (hibernation_prevented)
772 hildon_program_set_can_hibernate (app, FALSE);
774 /* Allow hibernation, after saving the state: */
775 modest_osso_save_state();
776 hildon_program_set_can_hibernate (app, TRUE);
783 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
785 GtkWidget *folder_win = (GtkWidget *) user_data;
786 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
788 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
789 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
790 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
792 gtk_widget_show (GTK_WIDGET (priv->folder_view));
794 /* Connect signals */
795 connect_signals ((ModestMainWindow*)self);
797 /* Set account store */
798 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
799 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
801 /* Load previous osso state, for instance if we are being restored from
803 modest_osso_load_state ();
805 /* Restore window & widget settings */
807 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
809 /* The UI spec wants us to show a connection dialog when the application is
810 * started by the user, if there is no connection.
811 * Do this before showing the account wizard,
812 * because wizard needs a connection to discover capabilities. */
813 modest_platform_connect_and_wait (GTK_WINDOW (self), NULL);
815 /* Check if accounts exist and show the account wizard if not */
816 gboolean accounts_exist =
817 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
819 if (!accounts_exist) {
820 /* This is necessary to have the main window shown behind the dialog
821 It's an ugly hack... jschmid */
822 gtk_widget_show_all(GTK_WIDGET(self));
823 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
826 GtkAction *send_receive_all;
827 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
828 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
829 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
830 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
831 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
832 modest_account_mgr_free_account_names (accounts);
837 modest_main_window_new (void)
839 ModestMainWindow *self = NULL;
840 ModestMainWindowPrivate *priv = NULL;
841 ModestWindowPrivate *parent_priv = NULL;
842 GtkWidget *folder_win = NULL;
843 ModestDimmingRulesGroup *menu_rules_group = NULL;
844 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
845 GtkActionGroup *action_group = NULL;
846 GError *error = NULL;
847 ModestConf *conf = NULL;
848 GtkAction *action = NULL;
849 GdkPixbuf *window_icon;
851 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
852 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
853 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
855 parent_priv->ui_manager = gtk_ui_manager_new();
856 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
858 action_group = gtk_action_group_new ("ModestMainWindowActions");
859 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
861 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
862 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
864 /* Add common actions */
865 gtk_action_group_add_actions (action_group,
866 modest_action_entries,
867 G_N_ELEMENTS (modest_action_entries),
870 gtk_action_group_add_actions (action_group,
871 modest_folder_view_action_entries,
872 G_N_ELEMENTS (modest_folder_view_action_entries),
875 gtk_action_group_add_actions (action_group,
876 modest_header_view_action_entries,
877 G_N_ELEMENTS (modest_header_view_action_entries),
880 gtk_action_group_add_toggle_actions (action_group,
881 modest_toggle_action_entries,
882 G_N_ELEMENTS (modest_toggle_action_entries),
885 gtk_action_group_add_toggle_actions (action_group,
886 modest_main_window_toggle_action_entries,
887 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
890 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
891 g_object_unref (action_group);
893 /* Load the UI definition */
894 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
895 MODEST_UIDIR "modest-main-window-ui.xml", &error);
897 g_warning ("Could not merge modest-ui.xml: %s", error->message);
898 g_error_free (error);
902 /* Add common dimming rules */
903 modest_dimming_rules_group_add_rules (menu_rules_group,
904 modest_main_window_menu_dimming_entries,
905 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
907 modest_dimming_rules_group_add_rules (toolbar_rules_group,
908 modest_main_window_toolbar_dimming_entries,
909 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
912 /* Insert dimming rules group for this window */
913 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
914 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
915 g_object_unref (menu_rules_group);
916 g_object_unref (toolbar_rules_group);
918 /* Add accelerators */
919 gtk_window_add_accel_group (GTK_WINDOW (self),
920 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
922 /* Menubar. Update the state of some toggles */
923 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
924 conf = modest_runtime_get_conf ();
925 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
926 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
927 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
928 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
929 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
930 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
931 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
932 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
933 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
934 gtk_widget_show (parent_priv->menubar);
936 /* Get device name */
937 modest_maemo_utils_get_device_name ();
941 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
942 if (!priv->header_view)
943 g_printerr ("modest: cannot instantiate header view\n");
944 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
945 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
946 MODEST_CONF_HEADER_VIEW_KEY);
948 /* Other style properties of header view */
949 g_object_set (G_OBJECT (priv->header_view),
952 /* gtk_widget_show (priv->header_view); */
955 priv->empty_view = create_empty_view ();
956 gtk_widget_show (priv->empty_view);
958 /* Create scrolled windows */
959 folder_win = gtk_scrolled_window_new (NULL, NULL);
960 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
961 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
963 GTK_POLICY_AUTOMATIC);
964 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
966 GTK_POLICY_AUTOMATIC);
967 /* gtk_widget_show (priv->contents_widget); */
970 priv->main_paned = gtk_hpaned_new ();
971 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
972 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
973 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
975 /* putting it all together... */
976 priv->main_vbox = gtk_vbox_new (FALSE, 6);
977 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
978 gtk_widget_show (priv->main_vbox);
980 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
982 HildonProgram *app = hildon_program_get_instance ();
983 hildon_program_add_window (app, HILDON_WINDOW (self));
985 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
986 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
988 g_signal_connect (G_OBJECT(self), "show",
989 G_CALLBACK (modest_main_window_on_show), folder_win);
991 /* Set window icon */
992 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
994 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
995 g_object_unref (window_icon);
998 /* Dont't restore settings here,
999 * because it requires a gtk_widget_show(),
1000 * and we don't want to do that until later,
1001 * so that the UI is not visible for non-menu D-Bus activation.
1003 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1005 return MODEST_WINDOW(self);
1009 modest_main_window_close_all (ModestMainWindow *self)
1012 GtkResponseType response;
1014 /* Create the confirmation dialog MSG-NOT308 */
1015 note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
1016 _("emev_nc_close_windows"),
1017 _("mcen_bd_yes"), GTK_RESPONSE_YES,
1018 _("mcen_bd_no"), GTK_RESPONSE_NO,
1021 response = gtk_dialog_run (GTK_DIALOG (note));
1022 gtk_widget_destroy (GTK_WIDGET (note));
1024 if (response == GTK_RESPONSE_YES)
1032 modest_main_window_set_style (ModestMainWindow *self,
1033 ModestMainWindowStyle style)
1035 ModestMainWindowPrivate *priv;
1036 ModestWindowPrivate *parent_priv;
1040 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1042 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1043 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1045 /* no change -> nothing to do */
1046 if (priv->style == style)
1049 /* Get toggle button and update the state if needed. This will
1050 happen only when the set_style is not invoked from the UI,
1051 for example when it's called from widget memory */
1052 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1053 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1054 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1055 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1056 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1057 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1058 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1061 priv->style = style;
1063 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1064 /* Remove main paned */
1065 g_object_ref (priv->main_paned);
1066 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1068 /* Reparent the contents widget to the main vbox */
1069 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1071 if (modest_header_view_has_selected_headers (MODEST_HEADER_VIEW (priv->header_view))) {
1072 TnyList *selection = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (priv->header_view));
1073 TnyIterator *iterator = tny_list_create_iterator (selection);
1075 tny_iterator_first (iterator);
1076 header = TNY_HEADER (tny_iterator_get_current (iterator));
1077 if (tny_header_get_subject (header))
1078 gtk_window_set_title (GTK_WINDOW(self), tny_header_get_subject (header));
1080 gtk_window_set_title (GTK_WINDOW (self), _("mail_va_no_subject"));
1083 g_object_unref (header);
1085 g_object_unref (iterator);
1086 g_object_unref (selection);
1090 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1091 /* Remove header view */
1092 g_object_ref (priv->contents_widget);
1093 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1095 /* Reparent the main paned */
1096 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1097 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1101 g_return_if_reached ();
1104 /* Let header view grab the focus if it's being shown */
1105 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1106 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1108 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1111 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1114 ModestMainWindowStyle
1115 modest_main_window_get_style (ModestMainWindow *self)
1117 ModestMainWindowPrivate *priv;
1119 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1121 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1128 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1130 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1131 ModestWindowPrivate *parent_priv;
1132 ModestWindowMgr *mgr;
1133 gboolean is_fullscreen;
1134 GtkAction *fs_toggle_action;
1137 mgr = modest_runtime_get_window_mgr ();
1139 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1141 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1143 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1144 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1145 if (is_fullscreen != active) {
1146 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1155 set_homogeneous (GtkWidget *widget,
1158 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1159 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1163 modest_main_window_show_toolbar (ModestWindow *self,
1164 gboolean show_toolbar)
1166 ModestMainWindowPrivate *priv = NULL;
1167 ModestWindowPrivate *parent_priv = NULL;
1168 GtkWidget *reply_button = NULL, *menu = NULL;
1169 GtkWidget *placeholder = NULL;
1172 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1173 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1174 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1176 /* Set optimized view status */
1177 priv->optimized_view = !show_toolbar;
1179 if (!parent_priv->toolbar) {
1180 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1183 /* Set homogeneous toolbar */
1184 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1185 set_homogeneous, NULL);
1187 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1188 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1189 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1190 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1191 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1192 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1193 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1194 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1196 /* Add ProgressBar (Transfer toolbar) */
1197 priv->progress_bar = modest_progress_bar_widget_new ();
1198 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1199 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1200 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1201 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1202 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1204 /* Connect cancel 'clicked' signal to abort progress mode */
1205 g_signal_connect(priv->cancel_toolitem, "clicked",
1206 G_CALLBACK(cancel_progressbar),
1209 /* Add it to the observers list */
1210 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1213 hildon_window_add_toolbar (HILDON_WINDOW (self),
1214 GTK_TOOLBAR (parent_priv->toolbar));
1216 /* Set reply button tap and hold menu */
1217 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1218 "/ToolBar/ToolbarMessageReply");
1219 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1220 "/ToolbarReplyCSM");
1221 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1223 /* Set send & receive button tap and hold menu */
1224 account_number_changed (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1229 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1230 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1231 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1233 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1234 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1236 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1241 compare_display_names (ModestAccountData *a,
1242 ModestAccountData *b)
1244 return strcmp (a->display_name, b->display_name);
1248 account_number_changed (TnyAccountStore *account_store,
1249 /* const gchar *account_name, */
1250 TnyAccount *account,
1253 GSList *account_names, *iter, *accounts;
1254 ModestMainWindow *self;
1255 ModestMainWindowPrivate *priv;
1256 ModestWindowPrivate *parent_priv;
1257 ModestAccountMgr *mgr;
1258 gint i, num_accounts;
1259 GtkActionGroup *action_group;
1261 gchar *default_account;
1262 GtkWidget *send_receive_button, *item;
1263 GtkAction *send_receive_all = NULL;
1265 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
1266 /* g_return_if_fail (TNY_IS_ACCOUNT (account)); */
1268 self = MODEST_MAIN_WINDOW (user_data);
1269 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1270 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1272 /* Get enabled account IDs */
1273 mgr = modest_runtime_get_account_mgr ();
1274 account_names = modest_account_mgr_account_names (mgr, TRUE);
1275 iter = account_names;
1279 ModestAccountData *account_data =
1280 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
1281 accounts = g_slist_prepend (accounts, account_data);
1285 modest_account_mgr_free_account_names (account_names);
1286 account_names = NULL;
1288 /* Order the list of accounts by its display name */
1289 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1290 num_accounts = g_slist_length (accounts);
1292 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1293 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1294 gtk_action_set_visible (send_receive_all, num_accounts > 1);
1296 /* Delete old send&receive popup items. We can not just do a
1297 menu_detach because it does not work well with
1299 if (priv->accounts_popup)
1300 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
1301 (GtkCallback) gtk_widget_destroy, NULL);
1303 /* Delete old entries in the View menu. Do not free groups, it
1305 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1307 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1308 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1309 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
1310 GTK_ACTION_GROUP (groups->data));
1313 if (priv->merge_ids) {
1314 for (i = 0; i < priv->merge_ids->len; i++)
1315 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1316 g_byte_array_free (priv->merge_ids, TRUE);
1318 /* We need to call this in order to ensure
1319 that the new actions are added in the right
1320 order (alphabetical */
1321 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1323 groups = g_list_next (groups);
1325 priv->merge_ids = g_byte_array_sized_new (num_accounts);
1327 /* Get send receive button */
1328 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1329 "/ToolBar/ToolbarSendReceive");
1331 /* Create the menu */
1332 if (num_accounts > 1) {
1333 if (!priv->accounts_popup)
1334 priv->accounts_popup = gtk_menu_new ();
1335 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1336 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1337 g_signal_connect (G_OBJECT (item),
1339 G_CALLBACK (on_send_receive_csm_activated),
1341 item = gtk_separator_menu_item_new ();
1342 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1345 /* Create a new action group */
1346 default_account = modest_account_mgr_get_default_account (mgr);
1347 action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1348 for (i = 0; i < num_accounts; i++) {
1349 gchar *display_name = NULL;
1351 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1353 /* Create display name. The UI specification specifies a different format string
1354 * to use for the default account, though both seem to be "%s", so
1355 * I don't see what the point is. murrayc. */
1356 if (default_account && account_data->account_name &&
1357 !(strcmp (default_account, account_data->account_name) == 0)) {
1358 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
1359 account_data->display_name);
1362 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
1363 account_data->display_name);
1366 /* Create action and add it to the action group. The
1367 action name must be the account name, this way we
1368 could know in the handlers the account to show */
1369 if(account_data && account_data->account_name) {
1370 gchar* item_name, *refresh_action_name;
1371 guint8 merge_id = 0;
1372 GtkAction *view_account_action, *refresh_account_action;
1374 view_account_action = gtk_action_new (account_data->account_name,
1375 display_name, NULL, NULL);
1376 gtk_action_group_add_action (action_group, view_account_action);
1378 /* Add ui from account data. We allow 2^9-1 account
1379 changes in a single execution because we're
1380 downcasting the guint to a guint8 in order to use a
1381 GByteArray. It should be enough. */
1382 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1383 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1384 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1385 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1387 "/MenuBar/ViewMenu/ViewMenuAdditions",
1389 account_data->account_name,
1390 GTK_UI_MANAGER_MENUITEM,
1393 /* Connect the action signal "activate" */
1394 g_signal_connect (G_OBJECT (view_account_action),
1396 G_CALLBACK (on_show_account_action_activated),
1399 /* Create the items for the Tools->Send&Receive submenu */
1400 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1401 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
1402 display_name, NULL, NULL);
1403 printf("DEBUG: %s: menu display_name=%s\n", __FUNCTION__, display_name);
1404 gtk_action_group_add_action (action_group, refresh_account_action);
1406 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1407 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1408 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1410 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1412 refresh_action_name,
1413 GTK_UI_MANAGER_MENUITEM,
1415 g_free (refresh_action_name);
1417 g_signal_connect_data (G_OBJECT (refresh_account_action),
1419 G_CALLBACK (on_refresh_account_action_activated),
1420 g_strdup (account_data->account_name),
1421 (GClosureNotify) g_free,
1424 /* Create item and add it to the send&receive
1425 CSM. If there is only one account then
1427 if (priv->accounts_popup) {
1428 GtkWidget *label = gtk_label_new(NULL);
1429 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1430 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
1432 gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
1433 gtk_label_set_markup (GTK_LABEL (label), escaped);
1438 gtk_label_set_text (GTK_LABEL (label), display_name);
1441 item = gtk_menu_item_new ();
1442 gtk_container_add (GTK_CONTAINER (item), label);
1444 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1445 g_signal_connect_data (G_OBJECT (item),
1447 G_CALLBACK (on_send_receive_csm_activated),
1448 g_strdup (account_data->account_name),
1449 (GClosureNotify) g_free,
1456 g_free (display_name);
1459 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1461 /* We cannot do this in the loop above because this relies on the action
1462 * group being inserted. This makes the default account appear in bold.
1463 * I agree it is a rather ugly way, but I don't see another possibility. armin. */
1464 for (i = 0; i < num_accounts; i++) {
1465 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1467 if(account_data->account_name && default_account &&
1468 strcmp (account_data->account_name, default_account) == 0) {
1469 gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1471 gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
1472 GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
1476 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
1477 if (GTK_IS_LABEL (child)) {
1478 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
1479 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
1480 gtk_label_set_markup (GTK_LABEL (child), bold_name);
1485 path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
1486 item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
1490 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
1491 if (GTK_IS_LABEL (child)) {
1492 const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
1493 gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
1494 gtk_label_set_markup (GTK_LABEL (child), bold_name);
1502 modest_account_mgr_free_account_data (mgr, account_data);
1505 if (priv->accounts_popup) {
1506 /* Mandatory in order to view the menu contents */
1507 gtk_widget_show_all (priv->accounts_popup);
1509 /* Setup tap_and_hold just if was not done before*/
1510 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1511 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1515 g_slist_free (accounts);
1516 g_free (default_account);
1519 /* Make sure that at least one account is viewed if there are any
1520 * accounts, for instance when adding the first account: */
1521 set_at_least_one_account_visible (self);
1525 * This function manages the key events used to navigate between
1526 * header and folder views (when the window is in split view)
1529 * -------------------------------------------------
1530 * HeaderView GDK_Left Move focus to folder view
1531 * FolderView GDK_Right Move focus to header view
1533 * There is no need to scroll to selected row, the widgets will be the
1534 * responsibles of doing that (probably managing the focus-in event
1537 on_inner_widgets_key_pressed (GtkWidget *widget,
1541 ModestMainWindowPrivate *priv;
1543 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1545 /* Do nothing if we're in SIMPLE style */
1546 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1549 if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1550 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1551 else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1552 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1558 set_alignment (GtkWidget *widget,
1561 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1562 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1566 create_empty_view (void)
1568 GtkLabel *label = NULL;
1569 GtkWidget *align = NULL;
1571 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1572 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1573 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1574 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1576 return GTK_WIDGET(align);
1580 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1582 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1587 gchar *gray_color_markup;
1589 vbox = gtk_vbox_new (FALSE, 0);
1591 /* Obtain the secondary text color. We need a realized widget, that's why
1592 we get styled_widget from outside */
1593 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1595 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1596 gray_color_markup = modest_text_utils_get_color_string (&color);
1598 // gray_color_markup is freed below
1599 gray_color_markup = g_strdup ("#BBBBBB");
1601 /* Account description: */
1603 if (modest_tny_account_is_virtual_local_folders (account)
1604 || (modest_tny_account_is_memory_card_account (account))) {
1606 /* Local folders: */
1608 /* Get device name */
1609 gchar *device_name = NULL;
1610 if (modest_tny_account_is_virtual_local_folders (account))
1611 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1612 MODEST_CONF_DEVICE_NAME, NULL);
1614 device_name = g_strdup (tny_account_get_name (account));
1616 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), ""); //TODO: Why the ""?
1617 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1618 gray_color_markup, tmp, device_name);
1620 label_w = gtk_label_new (NULL);
1621 gtk_label_set_markup (GTK_LABEL (label_w), label);
1622 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1623 g_free (device_name);
1626 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1627 gtk_box_pack_start (GTK_BOX (vbox),
1628 gtk_label_new (tny_account_get_name (account)),
1631 /* Other accounts, such as IMAP and POP: */
1636 /* Put proto in uppercase */
1637 proto = g_string_new (tny_account_get_proto (account));
1638 proto = g_string_ascii_up (proto);
1640 /* note: mcen_fi_localroot_description is something like "%s account"
1641 * however, we should display "%s account: %s"... therefore, ugly tmp */
1642 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1643 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1644 gray_color_markup, tmp, tny_account_get_name (account));
1647 label_w = gtk_label_new (NULL);
1648 gtk_label_set_markup (GTK_LABEL (label_w), label);
1649 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1650 g_string_free (proto, TRUE);
1656 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1657 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1658 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1659 modest_tny_folder_store_get_message_count (folder_store));
1660 label_w = gtk_label_new (NULL);
1661 gtk_label_set_markup (GTK_LABEL (label_w), label);
1662 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1666 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1668 _("mcen_fi_rootfolder_folders"),
1669 modest_tny_folder_store_get_folder_count (folder_store));
1670 label_w = gtk_label_new (NULL);
1671 gtk_label_set_markup (GTK_LABEL (label_w), label);
1672 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1676 if (modest_tny_account_is_virtual_local_folders (account)
1677 || modest_tny_account_is_memory_card_account (account)) {
1679 gchar *size = modest_text_utils_get_display_size (
1680 modest_tny_folder_store_get_local_size (folder_store));
1682 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1683 gray_color_markup, _("mcen_fi_rootfolder_size"),
1687 label_w = gtk_label_new (NULL);
1688 gtk_label_set_markup (GTK_LABEL (label_w), label);
1689 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1691 } else if (TNY_IS_ACCOUNT(folder_store)) {
1692 TnyAccount *account = TNY_ACCOUNT(folder_store);
1694 time_t last_updated;
1695 gchar *last_updated_string;
1696 /* Get last updated from configuration */
1697 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (),
1698 tny_account_get_id (account),
1699 MODEST_ACCOUNT_LAST_UPDATED,
1701 if (last_updated > 0)
1702 last_updated_string = modest_text_utils_get_display_date(last_updated);
1704 last_updated_string = g_strdup (_("mcen_va_never"));
1706 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1707 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1708 label_w = gtk_label_new (NULL);
1709 gtk_label_set_markup (GTK_LABEL (label_w), label);
1710 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1711 g_free (last_updated_string);
1715 g_free (gray_color_markup);
1718 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1724 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1726 ModestMainWindowPrivate *priv = NULL;
1728 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1730 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1732 return priv->send_receive_in_progress;
1736 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1738 GtkAction *action = NULL;
1739 GtkWidget *widget = NULL;
1740 ModestMainWindowPrivate *priv = NULL;
1742 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1743 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1745 priv->send_receive_in_progress = TRUE;
1747 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1748 gtk_action_set_sensitive (action, FALSE);
1749 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1750 /* gtk_action_set_sensitive (action, FALSE); */
1751 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1752 gtk_widget_set_sensitive (widget, FALSE);
1756 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1758 GtkAction *action = NULL;
1759 GtkWidget *widget = NULL;
1760 ModestMainWindowPrivate *priv = NULL;
1762 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1763 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1765 priv->send_receive_in_progress = FALSE;
1767 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1768 gtk_action_set_sensitive (action, TRUE);
1769 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1770 /* gtk_action_set_sensitive (action, TRUE); */
1771 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1772 gtk_widget_set_sensitive (widget, TRUE);
1777 _on_msg_count_changed (ModestHeaderView *header_view,
1779 TnyFolderChange *change,
1780 ModestMainWindow *main_window)
1782 printf ("DEBUG: %s\n", __FUNCTION__);
1783 gboolean folder_empty = FALSE;
1784 gboolean all_marked_as_deleted = FALSE;
1785 TnyFolderChangeChanged changed;
1786 ModestMainWindowPrivate *priv;
1788 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1789 g_return_if_fail (TNY_IS_FOLDER(folder));
1790 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1791 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1793 changed = tny_folder_change_get_changed (change);
1795 /* If something changes */
1796 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1797 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1799 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1801 printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1803 /* Check header removed (hide marked as DELETED headers) */
1804 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1805 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1808 /* Check if all messages are marked to be deleted */
1809 all_marked_as_deleted = modest_header_view_is_empty (header_view);
1810 folder_empty = folder_empty || all_marked_as_deleted ;
1812 /* Set contents style of headers view */
1814 modest_main_window_set_contents_style (main_window,
1815 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1816 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1819 modest_main_window_set_contents_style (main_window,
1820 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1826 modest_main_window_set_contents_style (ModestMainWindow *self,
1827 ModestMainWindowContentsStyle style)
1829 ModestMainWindowPrivate *priv;
1831 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1833 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1835 /* We allow to set the same content style than the previously
1836 set if there are details, because it could happen when we're
1837 selecting different accounts consecutively */
1838 if ((priv->contents_style == style) &&
1839 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1842 /* Remove previous child. Delete it if it was an account
1844 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1846 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1847 g_object_ref (content);
1848 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1849 g_object_ref (priv->empty_view);
1850 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1853 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1856 priv->contents_style = style;
1858 switch (priv->contents_style) {
1859 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1860 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1861 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1864 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1866 TnyFolderStore *selected_folderstore =
1867 modest_folder_view_get_selected (priv->folder_view);
1868 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1869 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1870 TNY_ACCOUNT (selected_folderstore));
1872 wrap_in_scrolled_window (priv->contents_widget,
1873 priv->details_widget);
1875 g_object_unref (selected_folderstore);
1876 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1882 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1883 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1884 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1888 g_return_if_reached ();
1892 gtk_widget_show_all (priv->contents_widget);
1895 ModestMainWindowContentsStyle
1896 modest_main_window_get_contents_style (ModestMainWindow *self)
1898 ModestMainWindowPrivate *priv;
1900 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1902 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1903 return priv->contents_style;
1908 on_configuration_key_changed (ModestConf* conf,
1910 ModestConfEvent event,
1911 ModestConfNotificationId id,
1912 ModestMainWindow *self)
1914 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1915 TnyAccount *account;
1918 priv->notification_id != id ||
1919 strcmp (key, MODEST_CONF_DEVICE_NAME))
1922 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1925 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1926 if (TNY_IS_ACCOUNT (account) &&
1927 !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1930 const gchar *device_name;
1934 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1935 label = GTK_LABEL (children->data);
1937 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1938 MODEST_CONF_DEVICE_NAME, NULL);
1940 new_text = g_strdup_printf ("%s: %s",
1941 _("mcen_fi_localroot_description"),
1944 gtk_label_set_text (label, new_text);
1945 gtk_widget_show (GTK_WIDGET (label));
1948 g_list_free (children);
1950 g_object_unref (account);
1954 set_toolbar_transfer_mode (ModestMainWindow *self)
1956 ModestMainWindowPrivate *priv = NULL;
1958 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1960 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1962 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1964 if (priv->progress_bar_timeout > 0) {
1965 g_source_remove (priv->progress_bar_timeout);
1966 priv->progress_bar_timeout = 0;
1973 set_toolbar_mode (ModestMainWindow *self,
1974 ModestToolBarModes mode)
1976 ModestWindowPrivate *parent_priv = NULL;
1977 ModestMainWindowPrivate *priv = NULL;
1978 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1980 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1982 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1983 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1985 /* In case this was called before the toolbar exists: */
1986 if (!(parent_priv->toolbar))
1989 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1991 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1992 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1993 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1995 /* Sets current toolbar mode */
1996 priv->current_toolbar_mode = mode;
1998 /* Show and hide toolbar items */
2000 case TOOLBAR_MODE_NORMAL:
2002 gtk_action_set_visible (sort_action, TRUE);
2004 gtk_action_set_visible (refresh_action, TRUE);
2005 if (priv->progress_toolitem) {
2006 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2007 gtk_widget_hide (priv->progress_toolitem);
2009 if (priv->progress_bar)
2010 gtk_widget_hide (priv->progress_bar);
2013 gtk_action_set_visible (cancel_action, FALSE);
2015 /* Hide toolbar if optimized view is enabled */
2016 if (priv->optimized_view)
2017 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2019 case TOOLBAR_MODE_TRANSFER:
2021 gtk_action_set_visible (sort_action, FALSE);
2023 gtk_action_set_visible (refresh_action, FALSE);
2025 gtk_action_set_visible (cancel_action, TRUE);
2026 if (priv->progress_toolitem) {
2027 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2028 gtk_widget_show (priv->progress_toolitem);
2030 if (priv->progress_bar)
2031 gtk_widget_show (priv->progress_bar);
2033 /* Show toolbar if it's hiden (optimized view ) */
2034 if (priv->optimized_view)
2035 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2038 g_return_if_reached ();
2043 cancel_progressbar (GtkToolButton *toolbutton,
2044 ModestMainWindow *self)
2047 ModestMainWindowPrivate *priv;
2049 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2051 /* Get operation observers and cancel all the operations */
2052 tmp = priv->progress_widgets;
2054 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2055 tmp=g_slist_next(tmp);
2060 observers_empty (ModestMainWindow *self)
2063 ModestMainWindowPrivate *priv;
2064 gboolean is_empty = TRUE;
2065 guint pending_ops = 0;
2067 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2068 tmp = priv->progress_widgets;
2070 /* Check all observers */
2071 while (tmp && is_empty) {
2072 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2073 is_empty = pending_ops == 0;
2075 tmp = g_slist_next(tmp);
2082 on_queue_changed (ModestMailOperationQueue *queue,
2083 ModestMailOperation *mail_op,
2084 ModestMailOperationQueueNotification type,
2085 ModestMainWindow *self)
2087 ModestMainWindowPrivate *priv;
2088 ModestMailOperationTypeOperation op_type;
2089 ModestToolBarModes mode;
2091 gboolean mode_changed = FALSE;
2093 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2094 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2096 /* Get toolbar mode from operation id*/
2097 op_type = modest_mail_operation_get_type_operation (mail_op);
2099 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2100 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2101 mode = TOOLBAR_MODE_TRANSFER;
2102 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2103 mode_changed = TRUE;
2106 mode = TOOLBAR_MODE_NORMAL;
2111 /* Add operation observers and change toolbar if neccessary*/
2112 tmp = priv->progress_widgets;
2114 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2115 if (mode == TOOLBAR_MODE_TRANSFER) {
2117 set_toolbar_transfer_mode(self);
2120 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2122 tmp = g_slist_next (tmp);
2126 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2127 /* Change toolbar mode */
2128 if (mode == TOOLBAR_MODE_TRANSFER) {
2130 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2132 tmp = g_slist_next (tmp);
2135 /* If no more operations are being observed, NORMAL mode is enabled again */
2136 if (observers_empty (self)) {
2137 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2147 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2149 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2151 /* Get account data */
2152 ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2153 ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2155 /* Set the new visible & active account */
2156 if (acc_data && acc_data->store_account) {
2157 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2158 acc_data->store_account->account_name);
2159 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2162 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2166 modest_account_mgr_free_account_data (mgr, acc_data);
2169 /* Make sure that at least one account is "viewed": */
2171 set_at_least_one_account_visible(ModestMainWindow *self)
2173 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2174 ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2176 if (!(priv->folder_view)) {
2177 /* It is too early to do this. */
2181 const gchar *active_server_account_name =
2182 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2183 if (!active_server_account_name ||
2184 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2186 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2187 if (first_modest_name) {
2188 set_account_visible (self, first_modest_name);
2189 g_free (first_modest_name);
2195 on_show_account_action_activated (GtkAction *action,
2198 ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2200 const gchar *acc_name = gtk_action_get_name (action);
2201 set_account_visible (self, acc_name);
2205 refresh_account (const gchar *account_name)
2209 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2211 /* If account_name == NULL, we must update all (option All) */
2213 modest_ui_actions_do_send_receive_all (win);
2215 modest_ui_actions_do_send_receive (account_name, win);
2220 on_refresh_account_action_activated (GtkAction *action,
2223 refresh_account ((const gchar*) user_data);
2227 on_send_receive_csm_activated (GtkMenuItem *item,
2230 refresh_account ((const gchar*) user_data);
2234 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2236 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2238 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2244 on_folder_view_focus_in (GtkWidget *widget,
2245 GdkEventFocus *event,
2248 ModestMainWindow *main_window = NULL;
2250 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2251 main_window = MODEST_MAIN_WINDOW (userdata);
2253 /* Update toolbar dimming state */
2254 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2260 on_header_view_focus_in (GtkWidget *widget,
2261 GdkEventFocus *event,
2264 ModestMainWindow *main_window = NULL;
2265 ModestMainWindowPrivate *priv = NULL;
2267 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2268 main_window = MODEST_MAIN_WINDOW (userdata);
2269 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2271 if (modest_header_view_has_selected_headers (MODEST_HEADER_VIEW (priv->header_view))) {
2272 TnyList *selection = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (priv->header_view));
2273 TnyIterator *iterator = tny_list_create_iterator (selection);
2276 tny_iterator_first (iterator);
2277 header = TNY_HEADER (tny_iterator_get_current (iterator));
2279 if (tny_header_get_subject (header))
2280 gtk_window_set_title (GTK_WINDOW(main_window), tny_header_get_subject (header));
2282 gtk_window_set_title (GTK_WINDOW (main_window), _("mail_va_no_subject"));
2285 g_object_unref (header);
2287 g_object_unref (iterator);
2288 g_object_unref (selection);
2292 /* Update toolbar dimming state */
2293 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2299 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2300 TnyFolderStore *folder_store,
2302 ModestMainWindow *main_window)
2304 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2305 GtkAction *action = NULL;
2306 gboolean show_reply = TRUE;
2307 gboolean show_forward = TRUE;
2308 gboolean show_cancel_send = FALSE;
2309 gboolean show_clipboard = TRUE;
2310 gboolean show_delete = TRUE;
2313 if (TNY_IS_ACCOUNT (folder_store)) {
2314 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2315 } else if (TNY_IS_FOLDER (folder_store)) {
2316 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2317 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2318 TNY_FOLDER (folder_store));
2319 switch (folder_type) {
2320 case TNY_FOLDER_TYPE_DRAFTS:
2321 show_clipboard = show_delete = TRUE;
2322 show_reply = show_forward = show_cancel_send = FALSE;
2324 case TNY_FOLDER_TYPE_SENT:
2325 show_forward = show_clipboard = show_delete = TRUE;
2326 show_reply = show_cancel_send = FALSE;
2328 case TNY_FOLDER_TYPE_OUTBOX:
2329 show_clipboard = show_delete = show_cancel_send = TRUE;
2330 show_reply = show_forward = FALSE;
2333 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2334 show_cancel_send = FALSE;
2337 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2338 show_cancel_send = FALSE;
2343 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2344 gtk_action_set_visible (action, show_reply);
2345 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2346 gtk_action_set_visible (action, show_reply);
2347 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2348 gtk_action_set_visible (action, show_forward);
2349 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2350 gtk_action_set_visible (action, show_cancel_send);
2351 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCut");
2352 gtk_action_set_visible (action, show_clipboard);
2353 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCopy");
2354 gtk_action_set_visible (action, show_clipboard);
2355 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMPaste");
2356 gtk_action_set_visible (action, show_clipboard);
2357 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2358 gtk_action_set_visible (action, show_delete);
2360 /* We finally call to the ui actions handler, after updating properly
2361 * the header view CSM */
2362 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2367 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2368 GtkTreeModel *model,
2369 GtkTreeRowReference *row_reference,
2370 ModestMainWindow *self)
2372 ModestMainWindowPrivate *priv = NULL;
2373 GtkTreeModel *header_model = NULL;
2374 GtkTreePath *path = NULL;
2376 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2377 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2378 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2380 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2381 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2383 /* Do nothing if we changed the folder in the main view */
2384 if (header_model != model)
2387 /* Select the message in the header view */
2388 path = gtk_tree_row_reference_get_path (row_reference);
2389 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2391 gtk_tree_path_free (path);