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"
67 #ifdef MODEST_HAVE_HILDON0_WIDGETS
68 #include <hildon-widgets/hildon-program.h>
70 #include <hildon/hildon-program.h>
71 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
73 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
80 /* 'private'/'protected' functions */
81 static void modest_main_window_class_init (ModestMainWindowClass *klass);
82 static void modest_main_window_init (ModestMainWindow *obj);
83 static void modest_main_window_finalize (GObject *obj);
84 static gboolean modest_main_window_window_state_event (GtkWidget *widget,
85 GdkEventWindowState *event,
88 static void connect_signals (ModestMainWindow *self);
90 static void restore_settings (ModestMainWindow *self, gboolean do_folder_view_too);
91 static void save_state (ModestWindow *self);
93 static void modest_main_window_show_toolbar (ModestWindow *window,
94 gboolean show_toolbar);
96 static void cancel_progressbar (GtkToolButton *toolbutton,
97 ModestMainWindow *self);
99 static void on_queue_changed (ModestMailOperationQueue *queue,
100 ModestMailOperation *mail_op,
101 ModestMailOperationQueueNotification type,
102 ModestMainWindow *self);
104 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
106 static void on_account_update (TnyAccountStore *account_store,
107 const gchar *account_name,
110 static gboolean on_inner_widgets_key_pressed (GtkWidget *widget,
114 static void on_configuration_key_changed (ModestConf* conf,
116 ModestConfEvent event,
117 ModestMainWindow *self);
119 static void set_toolbar_mode (ModestMainWindow *self,
120 ModestToolBarModes mode);
122 static gboolean set_toolbar_transfer_mode (ModestMainWindow *self);
124 static void on_show_account_action_activated (GtkAction *action,
127 static void on_refresh_account_action_activated (GtkAction *action,
130 static void on_send_receive_csm_activated (GtkMenuItem *item,
134 _on_msg_count_changed (ModestHeaderView *header_view,
136 TnyFolderChange *change,
137 ModestMainWindow *main_window);
140 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
143 static GtkWidget * create_empty_view (void);
146 on_folder_view_focus_in (GtkWidget *widget,
147 GdkEventFocus *event,
150 on_header_view_focus_in (GtkWidget *widget,
151 GdkEventFocus *event,
154 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
155 TnyFolderStore *folder_store,
157 ModestMainWindow *main_window);
159 /* list my signals */
166 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
167 struct _ModestMainWindowPrivate {
168 GtkWidget *msg_paned;
169 GtkWidget *main_paned;
170 GtkWidget *main_vbox;
171 GtkWidget *contents_widget;
172 GtkWidget *empty_view;
174 /* Progress observers */
175 GtkWidget *progress_bar;
176 GSList *progress_widgets;
179 GtkWidget *progress_toolitem;
180 GtkWidget *cancel_toolitem;
181 GtkWidget *sort_toolitem;
182 GtkWidget *refresh_toolitem;
183 ModestToolBarModes current_toolbar_mode;
185 /* Merge ids used to add/remove accounts to the ViewMenu*/
186 GByteArray *merge_ids;
188 /* On-demand widgets */
189 GtkWidget *accounts_popup;
190 GtkWidget *details_widget;
192 /* Optimized view enabled */
193 gboolean optimized_view;
195 /* Optimized view enabled */
196 gboolean send_receive_in_progress;
198 ModestHeaderView *header_view;
199 ModestFolderView *folder_view;
201 ModestMainWindowStyle style;
202 ModestMainWindowContentsStyle contents_style;
204 guint progress_bar_timeout;
206 /* Signal handler UIDs */
207 gint queue_changed_handler_uid;
208 GList *queue_err_signals;
210 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
211 MODEST_TYPE_MAIN_WINDOW, \
212 ModestMainWindowPrivate))
214 typedef struct _GetMsgAsyncHelper {
215 ModestMainWindowPrivate *main_window_private;
217 ModestTnyMsgReplyType reply_type;
218 ModestTnyMsgForwardType forward_type;
225 static GtkWindowClass *parent_class = NULL;
228 /* Private actions */
229 /* This is the context sensitive menu: */
230 static const GtkActionEntry modest_folder_view_action_entries [] = {
232 /* Folder View CSM actions */
233 { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
234 { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
235 { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_paste)},
236 { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
237 { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
238 { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
241 static const GtkActionEntry modest_header_view_action_entries [] = {
243 /* Header View CSM actions */
244 { "HeaderViewCSMOpen", NULL, N_("mcen_me_inbox_open"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_open) },
245 { "HeaderViewCSMReply", NULL, N_("mcen_me_inbox_reply"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply) },
246 { "HeaderViewCSMReplyAll", NULL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
247 { "HeaderViewCSMForward", NULL, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
248 { "HeaderViewCSMCut", NULL, N_("mcen_me_inbox_cut"), "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
249 { "HeaderViewCSMCopy", NULL, N_("mcen_me_inbox_copy"), "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
250 { "HeaderViewCSMPaste", NULL, N_("mcen_me_inbox_paste"), "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
251 { "HeaderViewCSMDelete", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
252 { "HeaderViewCSMCancelSending", NULL, N_("mcen_me_outbox_cancelsend"), NULL, NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
253 { "HeaderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
256 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
257 { "ToggleFolders", MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
260 /************************************************************************/
263 modest_main_window_get_type (void)
265 static GType my_type = 0;
267 static const GTypeInfo my_info = {
268 sizeof(ModestMainWindowClass),
269 NULL, /* base init */
270 NULL, /* base finalize */
271 (GClassInitFunc) modest_main_window_class_init,
272 NULL, /* class finalize */
273 NULL, /* class data */
274 sizeof(ModestMainWindow),
276 (GInstanceInitFunc) modest_main_window_init,
279 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
287 modest_main_window_class_init (ModestMainWindowClass *klass)
289 GObjectClass *gobject_class;
290 gobject_class = (GObjectClass*) klass;
291 ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
293 parent_class = g_type_class_peek_parent (klass);
294 gobject_class->finalize = modest_main_window_finalize;
296 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
298 modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
299 modest_window_class->save_state_func = save_state;
300 modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
301 modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
305 modest_main_window_init (ModestMainWindow *obj)
307 ModestMainWindowPrivate *priv;
309 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
311 priv->queue_err_signals = NULL;
312 priv->msg_paned = NULL;
313 priv->main_paned = NULL;
314 priv->main_vbox = NULL;
315 priv->header_view = NULL;
316 priv->folder_view = NULL;
317 priv->contents_widget = NULL;
318 priv->accounts_popup = NULL;
319 priv->details_widget = NULL;
320 priv->empty_view = NULL;
321 priv->progress_widgets = NULL;
322 priv->progress_bar = NULL;
323 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
324 priv->style = MODEST_MAIN_WINDOW_STYLE_SPLIT;
325 priv->contents_style = -1; /* invalid contents style. We need this to select it for the first time */
326 priv->merge_ids = NULL;
327 priv->optimized_view = FALSE;
328 priv->send_receive_in_progress = FALSE;
329 priv->progress_bar_timeout = 0;
330 priv->queue_changed_handler_uid = 0;
334 modest_main_window_finalize (GObject *obj)
336 ModestMainWindowPrivate *priv;
338 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
340 modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
342 g_slist_free (priv->progress_widgets);
344 g_byte_array_free (priv->merge_ids, TRUE);
346 if (priv->progress_bar_timeout > 0) {
347 g_source_remove (priv->progress_bar_timeout);
348 priv->progress_bar_timeout = 0;
351 /* Disconnect signal handlers */
352 if (priv->queue_changed_handler_uid)
353 g_signal_handler_disconnect (modest_runtime_get_mail_operation_queue (),
354 priv->queue_changed_handler_uid);
356 G_OBJECT_CLASS(parent_class)->finalize (obj);
360 modest_main_window_get_child_widget (ModestMainWindow *self,
361 ModestWidgetType widget_type)
363 ModestMainWindowPrivate *priv;
366 g_return_val_if_fail (self, NULL);
367 g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
370 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
372 switch (widget_type) {
373 case MODEST_WIDGET_TYPE_HEADER_VIEW:
374 widget = (GtkWidget*)priv->header_view; break;
375 case MODEST_WIDGET_TYPE_FOLDER_VIEW:
376 widget = (GtkWidget*)priv->folder_view; break;
381 return widget ? GTK_WIDGET(widget) : NULL;
386 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
388 printf ("DEBUGDEBUG: %s\n", __FUNCTION__);
391 ModestMainWindowPrivate *priv;
393 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
395 conf = modest_runtime_get_conf ();
397 modest_widget_memory_restore (conf, G_OBJECT(self),
398 MODEST_CONF_MAIN_WINDOW_KEY);
400 modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
401 MODEST_CONF_HEADER_VIEW_KEY);
403 if (do_folder_view_too)
404 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
405 MODEST_CONF_FOLDER_VIEW_KEY);
407 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
408 MODEST_CONF_MAIN_PANED_KEY);
410 /* We need to force a redraw here in order to get the right
411 position of the horizontal paned separator */
412 gtk_widget_show (GTK_WIDGET (self));
417 save_state (ModestWindow *window)
420 ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
421 ModestMainWindowPrivate *priv;
423 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
424 conf = modest_runtime_get_conf ();
426 modest_widget_memory_save (conf,G_OBJECT(self),
427 MODEST_CONF_MAIN_WINDOW_KEY);
428 modest_widget_memory_save (conf, G_OBJECT(priv->main_paned),
429 MODEST_CONF_MAIN_PANED_KEY);
430 // modest_widget_memory_save (conf, G_OBJECT(priv->header_view),
431 // MODEST_CONF_HEADER_VIEW_KEY);
432 modest_widget_memory_save (conf, G_OBJECT(priv->folder_view),
433 MODEST_CONF_FOLDER_VIEW_KEY);
437 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
439 if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
440 gtk_scrolled_window_add_with_viewport
441 (GTK_SCROLLED_WINDOW(win), widget);
443 gtk_container_add (GTK_CONTAINER(win),
448 /* static gboolean */
449 /* on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMainWindow *self) */
451 /* modest_window_save_state (MODEST_WINDOW(self)); */
456 on_sendqueue_error_happened (TnySendQueue *self, TnyHeader *header, TnyMsg *msg, GError *err, ModestMainWindow *user_data)
459 printf ("DEBUG: %s: err->code=%d, err->message=%s\n", __FUNCTION__, err->code, err->message);
461 if (err->code == TNY_ACCOUNT_ERROR_TRY_CONNECT_USER_CANCEL)
462 /* Don't show waste the user's time by showing him a dialog telling him
463 * that he has just cancelled something: */
467 /* Get the server name: */
468 const gchar* server_name = NULL;
470 TnyCamelTransportAccount* server_account = tny_camel_send_queue_get_transport_account (
471 TNY_CAMEL_SEND_QUEUE (self));
472 if (server_account) {
473 server_name = tny_account_get_hostname (TNY_ACCOUNT (server_account));
475 g_object_unref (server_account);
476 server_account = NULL;
480 server_name = _("Unknown Server");
482 /* Show the appropriate message text for the GError: */
483 gchar *message = NULL;
486 case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_HOST_LOOKUP_FAILED:
487 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name);
489 case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_SERVICE_UNAVAILABLE:
490 message = g_strdup_printf (_("emev_ib_ui_smtp_server_invalid"), server_name);
492 case TNY_TRANSPORT_ACCOUNT_ERROR_SEND_AUTHENTICATION_NOT_SUPPORTED:
493 /* TODO: This logical ID seems more suitable for a wrong username or password than for a
494 * wrong authentication method. The user is unlikely to guess at the real cause.
496 message = g_strdup_printf (_("eemev_ni_ui_smtp_authentication_fail_error"), server_name);
498 case TNY_TRANSPORT_ACCOUNT_ERROR_SEND:
500 message = g_strdup (_("emev_ib_ui_smtp_send_error"));
504 message = g_strdup (_("emev_ib_ui_smtp_send_error"));
507 modest_maemo_show_information_note_and_forget (GTK_WINDOW (user_data), message);
510 /* TODO: Offer to remove the message, to avoid messages in future? */
512 TnyFolder *outbox = tny_send_queue_get_outbox (queue);
513 tny_folder_remove_msg (outbox, header, NULL);
514 tny_folder_sync (outbox, TRUE, NULL);
515 g_object_unref (outbox);
525 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
527 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
529 GList *oerrsignals = priv->queue_err_signals;
530 while (oerrsignals) {
531 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
532 g_signal_handler_disconnect (esignal->queue, esignal->signal);
533 g_slice_free (QueueErrorSignal, esignal);
534 oerrsignals = g_list_next (oerrsignals);
536 g_list_free (priv->queue_err_signals);
537 priv->queue_err_signals = NULL;
541 on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self)
543 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
545 /* When going online, do the equivalent of pressing the send/receive button,
546 * as per the specification:
547 * (without the check for >0 accounts, though that is not specified): */
549 TnyDevice *device = tny_account_store_get_device (store);
551 /* modest_folder_view_update_model (MODEST_FOLDER_VIEW (priv->folder_view), store); */
553 /* Check that we are really online.
554 * This signal should not be emitted when we are not connected,
555 * but it seems to happen sometimes: */
556 if (!tny_device_is_online (device))
559 const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
560 printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id);
562 /* Stop the existing send queues: */
563 modest_runtime_remove_all_send_queues ();
565 /* Create the send queues again, using the appropriate transport accounts
566 * for this new connection.
567 * This could be the first time that they are created if this is the first
569 /* TODO: Does this really destroy the TnySendQueues and their threads
570 * We do not want 2 TnySendQueues to exist with the same underlying
571 * outbox directory. */
573 modest_main_window_cleanup_queue_error_signals (self);
575 GSList *account_names = modest_account_mgr_account_names (
576 modest_runtime_get_account_mgr(),
577 TRUE /* enabled accounts only */);
578 GSList *iter = account_names;
580 const gchar *account_name = (const gchar*)(iter->data);
582 TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (
583 modest_tny_account_store_get_transport_account_for_open_connection
584 (modest_runtime_get_account_store(), account_name));
586 /* Q: Is this the first location where the send-queues are requested? */
587 QueueErrorSignal *esignal = g_slice_new (QueueErrorSignal);
588 printf ("debug: %s:\n Transport account for %s: %s\n", __FUNCTION__, account_name,
589 tny_account_get_id(TNY_ACCOUNT(account)));
590 esignal->queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (account));
591 esignal->signal = g_signal_connect (G_OBJECT (esignal->queue), "error-happened",
592 G_CALLBACK (on_sendqueue_error_happened), self);
593 priv->queue_err_signals = g_list_prepend (priv->queue_err_signals, esignal);
597 iter = g_slist_next (iter);
600 modest_account_mgr_free_account_names (account_names);
601 account_names = NULL;
603 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self));
607 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
609 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
612 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
616 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
618 g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
620 /* Update visibility */
623 modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");
627 connect_signals (ModestMainWindow *self)
629 ModestWindowPrivate *parent_priv;
630 ModestMainWindowPrivate *priv;
633 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
634 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
637 g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
638 G_CALLBACK(on_inner_widgets_key_pressed), self);
639 g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
640 G_CALLBACK(modest_main_window_on_folder_selection_changed), self);
641 g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
642 G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
643 g_signal_connect (G_OBJECT (priv->folder_view), "focus-in-event",
644 G_CALLBACK (on_folder_view_focus_in), self);
646 /* Folder view CSM */
647 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
648 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
649 g_signal_connect (G_OBJECT(priv->folder_view), "tap-and-hold",
650 G_CALLBACK(_folder_view_csm_menu_activated),
653 g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
654 G_CALLBACK(modest_ui_actions_on_header_selected), self);
655 g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
656 G_CALLBACK(modest_ui_actions_on_header_activated), self);
657 g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
658 G_CALLBACK(modest_ui_actions_on_item_not_found), self);
659 g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
660 G_CALLBACK(on_inner_widgets_key_pressed), self);
661 g_signal_connect (G_OBJECT(priv->header_view), "msg_count_changed",
662 G_CALLBACK(_on_msg_count_changed), self);
663 g_signal_connect (G_OBJECT (priv->header_view), "focus-in-event",
664 G_CALLBACK (on_header_view_focus_in), self);
666 /* Header view CSM */
667 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
668 gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
669 g_signal_connect (G_OBJECT(priv->header_view), "tap-and-hold",
670 G_CALLBACK(_header_view_csm_menu_activated),
674 /* g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self); */
675 g_signal_connect (G_OBJECT (self), "window-state-event",
676 G_CALLBACK (modest_main_window_window_state_event),
679 /* Mail Operation Queue */
680 priv->queue_changed_handler_uid =
681 g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
682 "queue-changed", G_CALLBACK (on_queue_changed), self);
684 /* Track changes in the device name */
685 g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
686 "key_changed", G_CALLBACK (on_configuration_key_changed),
689 /* Track account changes. We need to refresh the toolbar */
690 g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
691 "account_update", G_CALLBACK (on_account_update),
695 g_signal_connect (G_OBJECT (modest_runtime_get_account_store()),
696 "password_requested",
697 G_CALLBACK (modest_ui_actions_on_password_requested), self);
700 g_signal_connect (G_OBJECT(modest_runtime_get_account_store()),
701 "connecting-finished",
702 G_CALLBACK(on_account_store_connecting_finished), self);
706 /** Idle handler, to send/receive at startup .*/
708 sync_accounts_cb (ModestMainWindow *win)
710 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
711 return FALSE; /* Do not call this idle handler again. */
715 static void on_hildon_program_is_topmost_notify(GObject *self,
716 GParamSpec *propert_param, gpointer user_data)
718 HildonProgram *app = HILDON_PROGRAM (self);
721 ModestWindow* self = MODEST_WINDOW(user_data);
724 /* Note that use of hildon_program_set_can_hibernate()
725 * is generally referred to as "setting the killable flag",
726 * though hibernation does not seem equal to death.
729 if (hildon_program_get_is_topmost (app)) {
730 /* Prevent hibernation when the progam comes to the foreground,
731 * because hibernation should only happen when the application
732 * is in the background: */
733 hildon_program_set_can_hibernate (app, FALSE);
735 /* Allow hibernation if the program has gone to the background: */
737 /* However, prevent hibernation while the settings are being changed: */
738 const gboolean hibernation_prevented =
739 modest_window_mgr_get_hibernation_is_prevented (
740 modest_runtime_get_window_mgr ());
742 if (hibernation_prevented)
743 hildon_program_set_can_hibernate (app, FALSE);
745 /* Allow hibernation, after saving the state: */
746 modest_osso_save_state();
747 hildon_program_set_can_hibernate (app, TRUE);
754 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
756 GtkWidget *folder_win = (GtkWidget *) user_data;
757 ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
759 priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
760 wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
761 /* wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
763 gtk_widget_show (GTK_WIDGET (priv->folder_view));
765 /* Connect signals */
766 connect_signals ((ModestMainWindow*)self);
768 /* Set account store */
769 tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
770 TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
772 /* Load previous osso state, for instance if we are being restored from
774 modest_osso_load_state ();
776 /* Restore window & widget settings */
778 restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
780 /* Check if accounts exist and show the account wizard if not */
781 gboolean accounts_exist =
782 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
784 if (!accounts_exist) {
785 /* This is necessary to have the main window shown behind the dialog
786 It's an ugly hack... jschmid */
787 gtk_widget_show_all(GTK_WIDGET(self));
788 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
791 GtkAction *send_receive_all;
792 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
793 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
794 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
795 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
796 gtk_action_set_visible (send_receive_all, g_slist_length (accounts));
797 modest_account_mgr_free_account_names (accounts);
804 modest_main_window_new (void)
806 ModestMainWindow *self = NULL;
807 ModestMainWindowPrivate *priv = NULL;
808 ModestWindowPrivate *parent_priv = NULL;
809 GtkWidget *folder_win = NULL;
810 ModestDimmingRulesGroup *menu_rules_group = NULL;
811 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
812 GtkActionGroup *action_group = NULL;
813 GError *error = NULL;
814 ModestConf *conf = NULL;
815 GtkAction *action = NULL;
816 GdkPixbuf *window_icon;
818 self = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
819 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
820 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
822 parent_priv->ui_manager = gtk_ui_manager_new();
823 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
825 action_group = gtk_action_group_new ("ModestMainWindowActions");
826 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
828 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
829 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
831 /* Add common actions */
832 gtk_action_group_add_actions (action_group,
833 modest_action_entries,
834 G_N_ELEMENTS (modest_action_entries),
837 gtk_action_group_add_actions (action_group,
838 modest_folder_view_action_entries,
839 G_N_ELEMENTS (modest_folder_view_action_entries),
842 gtk_action_group_add_actions (action_group,
843 modest_header_view_action_entries,
844 G_N_ELEMENTS (modest_header_view_action_entries),
847 gtk_action_group_add_toggle_actions (action_group,
848 modest_toggle_action_entries,
849 G_N_ELEMENTS (modest_toggle_action_entries),
852 gtk_action_group_add_toggle_actions (action_group,
853 modest_main_window_toggle_action_entries,
854 G_N_ELEMENTS (modest_main_window_toggle_action_entries),
857 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
858 g_object_unref (action_group);
860 /* Load the UI definition */
861 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
862 MODEST_UIDIR "modest-main-window-ui.xml", &error);
864 g_warning ("Could not merge modest-ui.xml: %s", error->message);
865 g_error_free (error);
869 /* Add common dimming rules */
870 modest_dimming_rules_group_add_rules (menu_rules_group,
871 modest_main_window_menu_dimming_entries,
872 G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
874 modest_dimming_rules_group_add_rules (toolbar_rules_group,
875 modest_main_window_toolbar_dimming_entries,
876 G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
879 /* Insert dimming rules group for this window */
880 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
881 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
882 g_object_unref (menu_rules_group);
883 g_object_unref (toolbar_rules_group);
885 /* Add accelerators */
886 gtk_window_add_accel_group (GTK_WINDOW (self),
887 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
889 /* Menubar. Update the state of some toggles */
890 parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
891 conf = modest_runtime_get_conf ();
892 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
893 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
894 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
895 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
896 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
897 "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
898 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
899 modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
900 hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
901 gtk_widget_show (parent_priv->menubar);
903 /* Get device name */
904 modest_maemo_utils_get_device_name ();
908 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
909 if (!priv->header_view)
910 g_printerr ("modest: cannot instantiate header view\n");
911 modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
912 modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
913 MODEST_CONF_HEADER_VIEW_KEY);
915 /* Other style properties of header view */
916 g_object_set (G_OBJECT (priv->header_view),
919 /* gtk_widget_show (priv->header_view); */
922 priv->empty_view = create_empty_view ();
923 gtk_widget_show (priv->empty_view);
925 /* Create scrolled windows */
926 folder_win = gtk_scrolled_window_new (NULL, NULL);
927 priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
928 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
930 GTK_POLICY_AUTOMATIC);
931 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
933 GTK_POLICY_AUTOMATIC);
934 /* gtk_widget_show (priv->contents_widget); */
937 priv->main_paned = gtk_hpaned_new ();
938 gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
939 gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
940 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
942 /* putting it all together... */
943 priv->main_vbox = gtk_vbox_new (FALSE, 6);
944 gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
945 gtk_widget_show (priv->main_vbox);
947 gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
949 HildonProgram *app = hildon_program_get_instance ();
950 hildon_program_add_window (app, HILDON_WINDOW (self));
952 g_signal_connect (G_OBJECT(app), "notify::is-topmost",
953 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
955 g_signal_connect (G_OBJECT(self), "show",
956 G_CALLBACK (modest_main_window_on_show), folder_win);
958 /* Set window icon */
959 window_icon = modest_platform_get_icon (MODEST_APP_ICON);
961 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
962 g_object_unref (window_icon);
965 /* Dont't restore settings here,
966 * because it requires a gtk_widget_show(),
967 * and we don't want to do that until later,
968 * so that the UI is not visible for non-menu D-Bus activation.
970 /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
972 return MODEST_WINDOW(self);
976 modest_main_window_close_all (ModestMainWindow *self)
979 GtkResponseType response;
981 /* Create the confirmation dialog MSG-NOT308 */
982 note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
983 _("emev_nc_close_windows"),
984 _("mcen_bd_yes"), GTK_RESPONSE_YES,
985 _("mcen_bd_no"), GTK_RESPONSE_NO,
988 response = gtk_dialog_run (GTK_DIALOG (note));
989 gtk_widget_destroy (GTK_WIDGET (note));
991 if (response == GTK_RESPONSE_YES)
999 modest_main_window_set_style (ModestMainWindow *self,
1000 ModestMainWindowStyle style)
1002 ModestMainWindowPrivate *priv;
1003 ModestWindowPrivate *parent_priv;
1007 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1009 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1010 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1012 /* no change -> nothing to do */
1013 if (priv->style == style)
1016 /* Get toggle button and update the state if needed. This will
1017 happen only when the set_style is not invoked from the UI,
1018 for example when it's called from widget memory */
1019 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1020 active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1021 if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1022 (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1023 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1024 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1025 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1028 priv->style = style;
1030 case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1031 /* Remove main paned */
1032 g_object_ref (priv->main_paned);
1033 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1035 /* Reparent the contents widget to the main vbox */
1036 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1038 if (modest_header_view_has_selected_headers (MODEST_HEADER_VIEW (priv->header_view))) {
1039 TnyList *selection = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (priv->header_view));
1040 TnyIterator *iterator = tny_list_create_iterator (selection);
1042 tny_iterator_first (iterator);
1043 header = TNY_HEADER (tny_iterator_get_current (iterator));
1044 if (tny_header_get_subject (header))
1045 gtk_window_set_title (GTK_WINDOW(self), tny_header_get_subject (header));
1047 gtk_window_set_title (GTK_WINDOW (self), _("mail_va_no_subject"));
1048 g_object_unref (header);
1049 g_object_unref (iterator);
1050 g_object_unref (selection);
1054 case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1055 /* Remove header view */
1056 g_object_ref (priv->contents_widget);
1057 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1059 /* Reparent the main paned */
1060 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1061 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1065 g_return_if_reached ();
1068 /* Let header view grab the focus if it's being shown */
1069 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1070 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1072 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1075 gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1078 ModestMainWindowStyle
1079 modest_main_window_get_style (ModestMainWindow *self)
1081 ModestMainWindowPrivate *priv;
1083 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1085 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1092 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1094 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1095 ModestWindowPrivate *parent_priv;
1096 ModestWindowMgr *mgr;
1097 gboolean is_fullscreen;
1098 GtkAction *fs_toggle_action;
1101 mgr = modest_runtime_get_window_mgr ();
1103 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1105 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1107 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1108 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1109 if (is_fullscreen != active) {
1110 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1119 set_homogeneous (GtkWidget *widget,
1122 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1123 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1127 modest_main_window_show_toolbar (ModestWindow *self,
1128 gboolean show_toolbar)
1130 ModestMainWindowPrivate *priv = NULL;
1131 ModestWindowPrivate *parent_priv = NULL;
1132 GtkWidget *reply_button = NULL, *menu = NULL;
1133 GtkWidget *placeholder = NULL;
1136 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1137 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1138 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1140 /* Set optimized view status */
1141 priv->optimized_view = !show_toolbar;
1143 if (!parent_priv->toolbar) {
1144 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1147 /* Set homogeneous toolbar */
1148 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1149 set_homogeneous, NULL);
1151 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1152 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1153 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1154 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1155 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1156 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1157 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1158 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1160 /* Add ProgressBar (Transfer toolbar) */
1161 priv->progress_bar = modest_progress_bar_widget_new ();
1162 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1163 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1164 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1165 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1166 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1168 /* Connect cancel 'clicked' signal to abort progress mode */
1169 g_signal_connect(priv->cancel_toolitem, "clicked",
1170 G_CALLBACK(cancel_progressbar),
1173 /* Add it to the observers list */
1174 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1177 hildon_window_add_toolbar (HILDON_WINDOW (self),
1178 GTK_TOOLBAR (parent_priv->toolbar));
1180 /* Set reply button tap and hold menu */
1181 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1182 "/ToolBar/ToolbarMessageReply");
1183 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1184 "/ToolbarReplyCSM");
1185 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1187 /* Set send & receive button tap and hold menu */
1188 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1193 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1194 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1195 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1197 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1198 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1200 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1205 compare_display_names (ModestAccountData *a,
1206 ModestAccountData *b)
1208 return strcmp (a->display_name, b->display_name);
1212 on_account_update (TnyAccountStore *account_store,
1213 const gchar *account_name,
1216 GSList *account_names, *iter, *accounts;
1217 ModestMainWindow *self;
1218 ModestMainWindowPrivate *priv;
1219 ModestWindowPrivate *parent_priv;
1220 ModestAccountMgr *mgr;
1221 gint i, num_accounts;
1222 GtkActionGroup *action_group;
1224 gchar *default_account;
1225 GtkWidget *send_receive_button, *item;
1226 GtkAction *send_receive_all = NULL;
1228 self = MODEST_MAIN_WINDOW (user_data);
1229 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1230 parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1232 /* Get enabled account IDs */
1233 mgr = modest_runtime_get_account_mgr ();
1234 account_names = modest_account_mgr_account_names (mgr, TRUE);
1235 iter = account_names;
1239 ModestAccountData *account_data =
1240 modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
1241 accounts = g_slist_prepend (accounts, account_data);
1245 modest_account_mgr_free_account_names (account_names);
1246 account_names = NULL;
1248 /* Order the list of accounts by its display name */
1249 accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1250 num_accounts = g_slist_length (accounts);
1252 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager,
1253 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1254 gtk_action_set_visible (send_receive_all, num_accounts > 1);
1256 /* Delete old send&receive popup items. We can not just do a
1257 menu_detach because it does not work well with
1259 if (priv->accounts_popup)
1260 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup),
1261 (GtkCallback) gtk_widget_destroy, NULL);
1263 /* Delete old entries in the View menu. Do not free groups, it
1265 groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1267 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1268 gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1269 gtk_ui_manager_remove_action_group (parent_priv->ui_manager,
1270 GTK_ACTION_GROUP (groups->data));
1273 if (priv->merge_ids) {
1274 for (i = 0; i < priv->merge_ids->len; i++)
1275 gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1276 g_byte_array_free (priv->merge_ids, TRUE);
1278 /* We need to call this in order to ensure
1279 that the new actions are added in the right
1280 order (alphabetical */
1281 gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1283 groups = g_list_next (groups);
1285 priv->merge_ids = g_byte_array_sized_new (num_accounts);
1287 /* Get send receive button */
1288 send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1289 "/ToolBar/ToolbarSendReceive");
1291 /* Create the menu */
1292 if (num_accounts > 1) {
1293 if (!priv->accounts_popup)
1294 priv->accounts_popup = gtk_menu_new ();
1295 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1296 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1297 g_signal_connect (G_OBJECT (item),
1299 G_CALLBACK (on_send_receive_csm_activated),
1301 item = gtk_separator_menu_item_new ();
1302 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1305 /* Create a new action group */
1306 default_account = modest_account_mgr_get_default_account (mgr);
1307 action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1308 for (i = 0; i < num_accounts; i++) {
1309 gchar *display_name = NULL;
1311 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1313 /* Create display name. The UI specification specifies a different format string
1314 * to use for the default account, though both seem to be "%s", so
1315 * I don't see what the point is. murrayc. */
1316 if (default_account && account_data->account_name &&
1317 !(strcmp (default_account, account_data->account_name) == 0)) {
1318 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"),
1319 account_data->display_name);
1322 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"),
1323 account_data->display_name);
1326 /* Create action and add it to the action group. The
1327 action name must be the account name, this way we
1328 could know in the handlers the account to show */
1329 if(account_data->account_name) {
1330 gchar* item_name, *refresh_action_name;
1332 GtkAction *view_account_action, *refresh_account_action;
1334 view_account_action = gtk_action_new (account_data->account_name,
1335 display_name, NULL, NULL);
1336 gtk_action_group_add_action (action_group, view_account_action);
1338 /* Add ui from account data. We allow 2^9-1 account
1339 changes in a single execution because we're
1340 downcasting the guint to a guint8 in order to use a
1341 GByteArray. It should be enough. */
1342 item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1343 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1344 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1345 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1347 "/MenuBar/ViewMenu/ViewMenuAdditions",
1349 account_data->account_name,
1350 GTK_UI_MANAGER_MENUITEM,
1353 /* Connect the action signal "activate" */
1354 g_signal_connect (G_OBJECT (view_account_action),
1356 G_CALLBACK (on_show_account_action_activated),
1359 /* Create the items for the Tools->Send&Receive submenu */
1360 refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1361 refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name,
1362 display_name, NULL, NULL);
1363 gtk_action_group_add_action (action_group, refresh_account_action);
1365 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1366 priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1367 gtk_ui_manager_add_ui (parent_priv->ui_manager,
1369 "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1371 refresh_action_name,
1372 GTK_UI_MANAGER_MENUITEM,
1374 g_free (refresh_action_name);
1376 g_signal_connect_data (G_OBJECT (refresh_account_action),
1378 G_CALLBACK (on_refresh_account_action_activated),
1379 g_strdup (account_data->account_name),
1380 (GClosureNotify) g_free,
1383 /* Create item and add it to the send&receive
1384 CSM. If there is only one account then
1386 if (priv->accounts_popup) {
1387 item = gtk_menu_item_new_with_label (display_name);
1388 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1389 g_signal_connect_data (G_OBJECT (item),
1391 G_CALLBACK (on_send_receive_csm_activated),
1392 g_strdup (account_data->account_name),
1393 (GClosureNotify) g_free,
1400 g_free (display_name);
1401 modest_account_mgr_free_account_data (mgr, account_data);
1403 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1405 if (priv->accounts_popup) {
1406 /* Mandatory in order to view the menu contents */
1407 gtk_widget_show_all (priv->accounts_popup);
1409 /* Setup tap_and_hold just if was not done before*/
1410 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1411 gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1415 g_slist_free (accounts);
1416 g_free (default_account);
1420 * This function manages the key events used to navigate between
1421 * header and folder views (when the window is in split view)
1424 * -------------------------------------------------
1425 * HeaderView GDK_Left Move focus to folder view
1426 * FolderView GDK_Right Move focus to header view
1428 * There is no need to scroll to selected row, the widgets will be the
1429 * responsibles of doing that (probably managing the focus-in event
1432 on_inner_widgets_key_pressed (GtkWidget *widget,
1436 ModestMainWindowPrivate *priv;
1438 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1440 /* Do nothing if we're in SIMPLE style */
1441 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1444 if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1445 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1446 else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1447 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1453 set_alignment (GtkWidget *widget,
1456 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1457 gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1461 create_empty_view (void)
1463 GtkLabel *label = NULL;
1464 GtkWidget *align = NULL;
1466 align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1467 label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1468 gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);
1469 gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1471 return GTK_WIDGET(align);
1475 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1477 /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1482 gchar *gray_color_markup;
1484 vbox = gtk_vbox_new (FALSE, 0);
1486 /* Obtain the secondary text color. We need a realized widget, that's why
1487 we get styled_widget from outside */
1488 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1490 gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1491 gray_color_markup = modest_text_utils_get_color_string (&color);
1493 // gray_color_markup is freed below
1494 gray_color_markup = g_strdup ("#BBBBBB");
1496 /* Account description: */
1498 if (modest_tny_account_is_virtual_local_folders (account)
1499 || (modest_tny_account_is_memory_card_account (account))) {
1501 /* Local folders: */
1503 /* Get device name */
1504 gchar *device_name = NULL;
1505 if (modest_tny_account_is_virtual_local_folders (account))
1506 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1507 MODEST_CONF_DEVICE_NAME, NULL);
1509 device_name = g_strdup (tny_account_get_name (account));
1511 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), ""); //TODO: Why the ""?
1512 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1513 gray_color_markup, tmp, device_name);
1515 label_w = gtk_label_new (NULL);
1516 gtk_label_set_markup (GTK_LABEL (label_w), label);
1517 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1518 g_free (device_name);
1521 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1522 gtk_box_pack_start (GTK_BOX (vbox),
1523 gtk_label_new (tny_account_get_name (account)),
1526 /* Other accounts, such as IMAP and POP: */
1531 /* Put proto in uppercase */
1532 proto = g_string_new (tny_account_get_proto (account));
1533 proto = g_string_ascii_up (proto);
1535 /* note: mcen_fi_localroot_description is something like "%s account"
1536 * however, we should display "%s account: %s"... therefore, ugly tmp */
1537 tmp = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1538 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1539 gray_color_markup, tmp, tny_account_get_name (account));
1542 label_w = gtk_label_new (NULL);
1543 gtk_label_set_markup (GTK_LABEL (label_w), label);
1544 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1545 g_string_free (proto, TRUE);
1551 TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1552 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d",
1553 gray_color_markup, _("mcen_fi_rootfolder_messages"),
1554 modest_tny_folder_store_get_message_count (folder_store));
1555 label_w = gtk_label_new (NULL);
1556 gtk_label_set_markup (GTK_LABEL (label_w), label);
1557 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1561 label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d",
1563 _("mcen_fi_rootfolder_folders"),
1564 modest_tny_folder_store_get_folder_count (folder_store));
1565 label_w = gtk_label_new (NULL);
1566 gtk_label_set_markup (GTK_LABEL (label_w), label);
1567 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1571 if (modest_tny_account_is_virtual_local_folders (account)
1572 || modest_tny_account_is_memory_card_account (account)) {
1574 gchar *size = modest_text_utils_get_display_size (
1575 modest_tny_folder_store_get_local_size (folder_store));
1577 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1578 gray_color_markup, _("mcen_fi_rootfolder_size"),
1582 label_w = gtk_label_new (NULL);
1583 gtk_label_set_markup (GTK_LABEL (label_w), label);
1584 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1586 } else if (TNY_IS_ACCOUNT(folder_store)) {
1587 TnyAccount *account = TNY_ACCOUNT(folder_store);
1589 time_t last_updated;
1590 gchar *last_updated_string;
1591 /* Get last updated from configuration */
1592 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (),
1593 tny_account_get_id (account),
1594 MODEST_ACCOUNT_LAST_UPDATED,
1596 if (last_updated > 0)
1597 last_updated_string = modest_text_utils_get_display_date(last_updated);
1599 last_updated_string = g_strdup (_("mcen_va_never"));
1601 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s",
1602 gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1603 label_w = gtk_label_new (NULL);
1604 gtk_label_set_markup (GTK_LABEL (label_w), label);
1605 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1606 g_free (last_updated_string);
1610 g_free (gray_color_markup);
1613 gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1619 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1621 ModestMainWindowPrivate *priv = NULL;
1623 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1625 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1627 return priv->send_receive_in_progress;
1631 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1633 GtkAction *action = NULL;
1634 GtkWidget *widget = NULL;
1635 ModestMainWindowPrivate *priv = NULL;
1637 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1638 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1640 priv->send_receive_in_progress = TRUE;
1642 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1643 gtk_action_set_sensitive (action, FALSE);
1644 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1645 /* gtk_action_set_sensitive (action, FALSE); */
1646 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1647 gtk_widget_set_sensitive (widget, FALSE);
1651 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1653 GtkAction *action = NULL;
1654 GtkWidget *widget = NULL;
1655 ModestMainWindowPrivate *priv = NULL;
1657 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1658 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1660 priv->send_receive_in_progress = FALSE;
1662 action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1663 gtk_action_set_sensitive (action, TRUE);
1664 /* action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1665 /* gtk_action_set_sensitive (action, TRUE); */
1666 widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1667 gtk_widget_set_sensitive (widget, TRUE);
1672 _on_msg_count_changed (ModestHeaderView *header_view,
1674 TnyFolderChange *change,
1675 ModestMainWindow *main_window)
1677 printf ("DEBUG: %s\n", __FUNCTION__);
1678 gboolean folder_empty = FALSE;
1679 TnyFolderChangeChanged changed;
1681 g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1682 g_return_if_fail (TNY_IS_FOLDER(folder));
1683 g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1685 changed = tny_folder_change_get_changed (change);
1687 /* If something changes */
1688 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1689 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1691 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1693 printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1695 /* Set contents style of headers view */
1697 modest_main_window_set_contents_style (main_window,
1698 MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1701 modest_main_window_set_contents_style (main_window,
1702 MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1708 modest_main_window_set_contents_style (ModestMainWindow *self,
1709 ModestMainWindowContentsStyle style)
1711 ModestMainWindowPrivate *priv;
1713 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1715 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1717 /* We allow to set the same content style than the previously
1718 set if there are details, because it could happen when we're
1719 selecting different accounts consecutively */
1720 if ((priv->contents_style == style) &&
1721 (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1724 /* Remove previous child. Delete it if it was an account
1726 GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1728 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1729 g_object_ref (content);
1730 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1731 g_object_ref (priv->empty_view);
1732 gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1735 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1738 priv->contents_style = style;
1740 switch (priv->contents_style) {
1741 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1742 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1743 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1746 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1748 TnyFolderStore *selected_folderstore =
1749 modest_folder_view_get_selected (priv->folder_view);
1750 if (TNY_IS_ACCOUNT (selected_folderstore)) {
1751 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1752 TNY_ACCOUNT (selected_folderstore));
1754 wrap_in_scrolled_window (priv->contents_widget,
1755 priv->details_widget);
1757 g_object_unref (selected_folderstore);
1758 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1764 case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1765 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1766 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1770 g_return_if_reached ();
1774 gtk_widget_show_all (priv->contents_widget);
1777 ModestMainWindowContentsStyle
1778 modest_main_window_get_contents_style (ModestMainWindow *self)
1780 ModestMainWindowPrivate *priv;
1782 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1784 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1785 return priv->contents_style;
1790 on_configuration_key_changed (ModestConf* conf,
1792 ModestConfEvent event,
1793 ModestMainWindow *self)
1795 ModestMainWindowPrivate *priv;
1796 TnyAccount *account;
1798 if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1801 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1803 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1806 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1807 if (TNY_IS_ACCOUNT (account) &&
1808 !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1811 const gchar *device_name;
1815 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1816 label = GTK_LABEL (children->data);
1818 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1819 MODEST_CONF_DEVICE_NAME, NULL);
1821 new_text = g_strdup_printf ("%s: %s",
1822 _("mcen_fi_localroot_description"),
1825 gtk_label_set_text (label, new_text);
1826 gtk_widget_show (GTK_WIDGET (label));
1829 g_list_free (children);
1831 g_object_unref (account);
1835 set_toolbar_transfer_mode (ModestMainWindow *self)
1837 ModestMainWindowPrivate *priv = NULL;
1839 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1841 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1843 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1845 if (priv->progress_bar_timeout > 0) {
1846 g_source_remove (priv->progress_bar_timeout);
1847 priv->progress_bar_timeout = 0;
1854 set_toolbar_mode (ModestMainWindow *self,
1855 ModestToolBarModes mode)
1857 ModestWindowPrivate *parent_priv = NULL;
1858 ModestMainWindowPrivate *priv = NULL;
1859 GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1861 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1863 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1864 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1866 /* In case this was called before the toolbar exists: */
1867 if (!(parent_priv->toolbar))
1870 g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar));
1872 sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1873 refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1874 cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1876 /* Sets current toolbar mode */
1877 priv->current_toolbar_mode = mode;
1879 /* Show and hide toolbar items */
1881 case TOOLBAR_MODE_NORMAL:
1883 gtk_action_set_visible (sort_action, TRUE);
1885 gtk_action_set_visible (refresh_action, TRUE);
1886 if (priv->progress_toolitem) {
1887 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1888 gtk_widget_hide (priv->progress_toolitem);
1890 if (priv->progress_bar)
1891 gtk_widget_hide (priv->progress_bar);
1894 gtk_action_set_visible (cancel_action, FALSE);
1895 /* if (priv->sort_toolitem) */
1896 /* gtk_widget_show (priv->sort_toolitem); */
1898 /* if (priv->refresh_toolitem) */
1899 /* gtk_widget_show (priv->refresh_toolitem); */
1901 /* if (priv->progress_toolitem) */
1902 /* gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE); */
1903 /* if (priv->progress_bar) */
1904 /* gtk_widget_hide (priv->progress_bar); */
1906 /* if (priv->cancel_toolitem) */
1907 /* gtk_widget_hide (priv->cancel_toolitem); */
1909 /* Hide toolbar if optimized view is enabled */
1910 if (priv->optimized_view)
1911 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1913 case TOOLBAR_MODE_TRANSFER:
1915 gtk_action_set_visible (sort_action, FALSE);
1917 gtk_action_set_visible (refresh_action, FALSE);
1919 gtk_action_set_visible (cancel_action, TRUE);
1920 if (priv->progress_toolitem) {
1921 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1922 gtk_widget_show (priv->progress_toolitem);
1924 if (priv->progress_bar)
1925 gtk_widget_show (priv->progress_bar);
1927 /* if (priv->sort_toolitem) */
1928 /* gtk_widget_hide (priv->sort_toolitem); */
1930 /* if (priv->refresh_toolitem) */
1931 /* gtk_widget_hide (priv->refresh_toolitem); */
1933 /* if (priv->progress_toolitem) */
1934 /* gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE); */
1935 /* if (priv->progress_bar) */
1936 /* gtk_widget_show (priv->progress_bar); */
1938 /* if (priv->cancel_toolitem) */
1939 /* gtk_widget_show (priv->cancel_toolitem); */
1941 /* Show toolbar if it's hiden (optimized view ) */
1942 if (priv->optimized_view)
1943 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1946 g_return_if_reached ();
1951 cancel_progressbar (GtkToolButton *toolbutton,
1952 ModestMainWindow *self)
1955 ModestMainWindowPrivate *priv;
1957 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1959 /* Get operation observers and cancel its current operation */
1960 tmp = priv->progress_widgets;
1962 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1963 tmp=g_slist_next(tmp);
1968 observers_empty (ModestMainWindow *self)
1971 ModestMainWindowPrivate *priv;
1972 gboolean is_empty = TRUE;
1973 guint pending_ops = 0;
1975 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1976 tmp = priv->progress_widgets;
1978 /* Check all observers */
1979 while (tmp && is_empty) {
1980 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1981 is_empty = pending_ops == 0;
1983 tmp = g_slist_next(tmp);
1990 on_queue_changed (ModestMailOperationQueue *queue,
1991 ModestMailOperation *mail_op,
1992 ModestMailOperationQueueNotification type,
1993 ModestMainWindow *self)
1995 ModestMainWindowPrivate *priv;
1996 ModestMailOperationTypeOperation op_type;
1997 ModestToolBarModes mode;
1999 gboolean mode_changed = FALSE;
2000 /* ModestMailOperationStatus status; */
2002 g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2003 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2005 /* Get toolbar mode from operation id*/
2006 op_type = modest_mail_operation_get_type_operation (mail_op);
2008 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2009 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2010 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2011 mode = TOOLBAR_MODE_TRANSFER;
2012 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2013 mode_changed = TRUE;
2016 mode = TOOLBAR_MODE_NORMAL;
2021 /* Add operation observers and change toolbar if neccessary*/
2022 tmp = priv->progress_widgets;
2024 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2025 if (mode == TOOLBAR_MODE_TRANSFER) {
2027 set_toolbar_transfer_mode(self);
2029 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2031 tmp = g_slist_next (tmp);
2035 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2036 /* Change toolbar mode */
2037 if (mode == TOOLBAR_MODE_TRANSFER) {
2039 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2041 tmp = g_slist_next (tmp);
2044 /* If no more operations are being observed, NORMAL mode is enabled again */
2045 if (observers_empty (self)) {
2046 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2057 on_show_account_action_activated (GtkAction *action,
2060 ModestAccountData *acc_data;
2061 ModestMainWindow *self;
2062 ModestMainWindowPrivate *priv;
2063 ModestAccountMgr *mgr;
2064 const gchar *acc_name;
2066 self = MODEST_MAIN_WINDOW (user_data);
2067 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2069 /* Get account data */
2070 acc_name = gtk_action_get_name (action);
2071 mgr = modest_runtime_get_account_mgr ();
2072 acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2074 /* Set the new visible & active account */
2075 if (acc_data->store_account) {
2076 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2077 acc_data->store_account->account_name);
2078 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2081 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2084 modest_account_mgr_free_account_data (mgr, acc_data);
2088 refresh_account (const gchar *account_name)
2092 win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2094 /* If account_name == NULL, we must update all (option All) */
2096 modest_ui_actions_do_send_receive_all (win);
2098 modest_ui_actions_do_send_receive (account_name, win);
2103 on_refresh_account_action_activated (GtkAction *action,
2106 refresh_account ((const gchar*) user_data);
2110 on_send_receive_csm_activated (GtkMenuItem *item,
2113 refresh_account ((const gchar*) user_data);
2117 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2119 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2121 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2127 on_folder_view_focus_in (GtkWidget *widget,
2128 GdkEventFocus *event,
2131 ModestMainWindow *main_window = NULL;
2133 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2134 main_window = MODEST_MAIN_WINDOW (userdata);
2136 /* Update toolbar dimming state */
2137 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2143 on_header_view_focus_in (GtkWidget *widget,
2144 GdkEventFocus *event,
2147 ModestMainWindow *main_window = NULL;
2148 ModestMainWindowPrivate *priv = NULL;
2150 g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2151 main_window = MODEST_MAIN_WINDOW (userdata);
2152 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2154 if (modest_header_view_has_selected_headers (MODEST_HEADER_VIEW (priv->header_view))) {
2155 TnyList *selection = modest_header_view_get_selected_headers (MODEST_HEADER_VIEW (priv->header_view));
2156 TnyIterator *iterator = tny_list_create_iterator (selection);
2159 tny_iterator_first (iterator);
2160 header = TNY_HEADER (tny_iterator_get_current (iterator));
2162 if (tny_header_get_subject (header))
2163 gtk_window_set_title (GTK_WINDOW(main_window), tny_header_get_subject (header));
2165 gtk_window_set_title (GTK_WINDOW (main_window), _("mail_va_no_subject"));
2167 g_object_unref (header);
2168 g_object_unref (iterator);
2169 g_object_unref (selection);
2173 /* Update toolbar dimming state */
2174 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2180 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2181 TnyFolderStore *folder_store,
2183 ModestMainWindow *main_window)
2185 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2186 GtkAction *action = NULL;
2187 gboolean show_reply = TRUE;
2188 gboolean show_forward = TRUE;
2189 gboolean show_cancel_send = FALSE;
2190 gboolean show_clipboard = TRUE;
2191 gboolean show_delete = TRUE;
2194 if (TNY_IS_ACCOUNT (folder_store)) {
2195 show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2196 } else if (TNY_IS_FOLDER (folder_store)) {
2197 if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2198 TnyFolderType folder_type = modest_tny_folder_get_local_folder_type (
2199 TNY_FOLDER (folder_store));
2200 switch (folder_type) {
2201 case TNY_FOLDER_TYPE_DRAFTS:
2202 show_clipboard = show_delete = TRUE;
2203 show_reply = show_forward = show_cancel_send = FALSE;
2205 case TNY_FOLDER_TYPE_SENT:
2206 show_forward = show_clipboard = show_delete = TRUE;
2207 show_reply = show_cancel_send = FALSE;
2209 case TNY_FOLDER_TYPE_OUTBOX:
2210 show_clipboard = show_delete = show_cancel_send = TRUE;
2211 show_reply = show_forward = FALSE;
2214 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2215 show_cancel_send = FALSE;
2218 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2219 show_cancel_send = FALSE;
2224 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2225 gtk_action_set_visible (action, show_reply);
2226 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2227 gtk_action_set_visible (action, show_reply);
2228 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2229 gtk_action_set_visible (action, show_forward);
2230 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2231 gtk_action_set_visible (action, show_cancel_send);
2232 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCut");
2233 gtk_action_set_visible (action, show_clipboard);
2234 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCopy");
2235 gtk_action_set_visible (action, show_clipboard);
2236 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMPaste");
2237 gtk_action_set_visible (action, show_clipboard);
2238 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2239 gtk_action_set_visible (action, show_delete);
2241 /* We finally call to the ui actions handler, after updating properly
2242 * the header view CSM */
2243 modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2248 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2249 GtkTreeModel *model,
2250 GtkTreeRowReference *row_reference,
2251 ModestMainWindow *self)
2253 ModestMainWindowPrivate *priv = NULL;
2254 GtkTreeModel *header_model = NULL;
2255 GtkTreePath *path = NULL;
2257 g_return_val_if_fail (MODEST_MSG_VIEW_WINDOW (view_window), FALSE);
2258 g_return_val_if_fail (MODEST_MAIN_WINDOW (self), FALSE);
2259 g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2261 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2262 header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2264 /* Do nothing if we changed the folder in the main view */
2265 if (header_model != model)
2268 /* Select the message in the header view */
2269 path = gtk_tree_row_reference_get_path (row_reference);
2270 _modest_header_view_select_from_path (MODEST_HEADER_VIEW (priv->header_view), path);
2271 gtk_tree_path_free (path);