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.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include <tny-error.h>
37 #include "modest-marshal.h"
38 #include "modest-platform.h"
39 #include <modest-utils.h>
40 #include <modest-maemo-utils.h>
41 #include <modest-tny-msg.h>
42 #include <modest-msg-view-window.h>
43 #include <modest-main-window-ui.h>
44 #include "modest-msg-view-window-ui-dimming.h"
45 #include <modest-widget-memory.h>
46 #include <modest-progress-object.h>
47 #include <modest-runtime.h>
48 #include <modest-window-priv.h>
49 #include <modest-tny-folder.h>
50 #include <modest-text-utils.h>
51 #include <modest-account-mgr-helpers.h>
52 #include <hildon/hildon-pannable-area.h>
53 #include <hildon/hildon-picker-dialog.h>
54 #include <hildon/hildon-app-menu.h>
55 #include "modest-defs.h"
56 #include "modest-hildon-includes.h"
57 #include "modest-ui-dimming-manager.h"
58 #include <gdk/gdkkeysyms.h>
59 #include <modest-tny-account.h>
60 #include <modest-mime-part-view.h>
61 #include <modest-isearch-view.h>
62 #include <modest-tny-mime-part.h>
63 #include <modest-address-book.h>
66 #include <glib/gstdio.h>
67 #include <modest-debug.h>
68 #include <modest-header-window.h>
69 #include <modest-account-protocol.h>
70 #include <modest-hildon2-window-mgr.h>
71 #include <tny-camel-msg.h>
72 #include <tny-camel-bs-mime-part.h>
73 #include <tny-camel-bs-msg.h>
75 #include <X11/Xatom.h>
76 #include <X11/XKBlib.h>
77 #include <X11/Xdmcp.h>
79 #define MYDOCS_ENV "MYDOCSDIR"
80 #define DOCS_FOLDER ".documents"
82 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
83 struct _ModestMsgViewWindowPrivate {
86 GtkWidget *main_scroll;
87 GtkWidget *find_toolbar;
90 /* Progress observers */
91 GSList *progress_widgets;
94 GtkWidget *prev_toolitem;
95 GtkWidget *next_toolitem;
96 gboolean progress_hint;
99 /* Optimized view enabled */
100 gboolean optimized_view;
102 /* Whether this was created via the *_new_for_search_result() function. */
103 gboolean is_search_result;
105 /* Whether the message is in outbox */
108 /* A reference to the @model of the header view
109 * to allow selecting previous/next messages,
110 * if the message is currently selected in the header view.
112 const gchar *header_folder_id;
113 GtkTreeModel *header_model;
114 GtkTreeRowReference *row_reference;
115 GtkTreeRowReference *next_row_reference;
117 gulong clipboard_change_handler;
118 gulong queue_change_handler;
119 gulong account_removed_handler;
120 gulong row_changed_handler;
121 gulong row_deleted_handler;
122 gulong row_inserted_handler;
123 gulong rows_reordered_handler;
124 gulong fetch_image_redraw_handler;
127 GtkWidget *remove_attachment_banner;
130 TnyMimePart *other_body;
136 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
137 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
138 static void modest_header_view_observer_init (ModestHeaderViewObserverIface *iface_class);
139 static void modest_msg_view_window_finalize (GObject *obj);
140 static void modest_msg_view_window_show_find_toolbar (GtkWidget *obj, gpointer data);
141 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
142 ModestMsgViewWindow *obj);
143 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
144 ModestMsgViewWindow *obj);
145 static void modest_msg_view_window_toggle_find_toolbar (GtkWidget *obj,
147 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
149 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
150 static void modest_msg_view_window_set_zoom (ModestWindow *window,
152 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
153 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
154 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
157 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
159 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
160 gboolean show_toolbar);
162 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
164 ModestMsgViewWindow *window);
166 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
169 ModestMsgViewWindow *window);
171 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
173 ModestMsgViewWindow *window);
175 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
176 GtkTreePath *tree_path,
177 GtkTreeIter *tree_iter,
178 ModestMsgViewWindow *window);
180 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
184 ModestMsgViewWindow *window);
186 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
188 const gchar *tny_folder_id);
190 static void on_queue_changed (ModestMailOperationQueue *queue,
191 ModestMailOperation *mail_op,
192 ModestMailOperationQueueNotification type,
193 ModestMsgViewWindow *self);
195 static void on_account_removed (TnyAccountStore *account_store,
199 static void on_move_focus (GtkWidget *widget,
200 GtkDirectionType direction,
203 static void view_msg_cb (ModestMailOperation *mail_op,
210 static void set_progress_hint (ModestMsgViewWindow *self,
213 static void update_window_title (ModestMsgViewWindow *window);
215 static void init_window (ModestMsgViewWindow *obj);
217 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
219 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
221 static gboolean on_fetch_image (ModestMsgView *msgview,
224 ModestMsgViewWindow *window);
226 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
227 GtkScrollType scroll_type,
230 static gboolean message_reader (ModestMsgViewWindow *window,
231 ModestMsgViewWindowPrivate *priv,
233 const gchar *msg_uid,
235 GtkTreeRowReference *row_reference);
237 static void setup_menu (ModestMsgViewWindow *self);
238 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
241 static void update_branding (ModestMsgViewWindow *self);
242 static void sync_flags (ModestMsgViewWindow *self);
243 static gboolean on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part,
244 GtkContainer *container, ModestMsgViewWindow *self);
246 static gboolean on_realize (GtkWidget *widget,
249 /* list my signals */
256 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
257 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
260 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
261 MODEST_TYPE_MSG_VIEW_WINDOW, \
262 ModestMsgViewWindowPrivate))
264 static GtkWindowClass *parent_class = NULL;
266 /* uncomment the following if you have defined any signals */
267 static guint signals[LAST_SIGNAL] = {0};
270 modest_msg_view_window_get_type (void)
272 static GType my_type = 0;
274 static const GTypeInfo my_info = {
275 sizeof(ModestMsgViewWindowClass),
276 NULL, /* base init */
277 NULL, /* base finalize */
278 (GClassInitFunc) modest_msg_view_window_class_init,
279 NULL, /* class finalize */
280 NULL, /* class data */
281 sizeof(ModestMsgViewWindow),
283 (GInstanceInitFunc) modest_msg_view_window_init,
286 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
287 "ModestMsgViewWindow",
290 static const GInterfaceInfo modest_header_view_observer_info =
292 (GInterfaceInitFunc) modest_header_view_observer_init,
293 NULL, /* interface_finalize */
294 NULL /* interface_data */
297 g_type_add_interface_static (my_type,
298 MODEST_TYPE_HEADER_VIEW_OBSERVER,
299 &modest_header_view_observer_info);
305 save_state (ModestWindow *self)
307 modest_widget_memory_save (modest_runtime_get_conf (),
309 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
313 modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
314 GtkScrollType scroll_type,
318 ModestMsgViewWindowPrivate *priv;
321 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
323 switch (scroll_type) {
324 case GTK_SCROLL_STEP_UP:
327 case GTK_SCROLL_STEP_DOWN:
330 case GTK_SCROLL_PAGE_UP:
333 case GTK_SCROLL_PAGE_DOWN:
336 case GTK_SCROLL_START:
347 modest_maemo_utils_scroll_pannable((HildonPannableArea *) priv->main_scroll, 0, step);
349 return (gboolean) step;
353 add_scroll_binding (GtkBindingSet *binding_set,
355 GtkScrollType scroll)
357 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
359 gtk_binding_entry_add_signal (binding_set, keyval, 0,
361 GTK_TYPE_SCROLL_TYPE, scroll,
362 G_TYPE_BOOLEAN, FALSE);
363 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
365 GTK_TYPE_SCROLL_TYPE, scroll,
366 G_TYPE_BOOLEAN, FALSE);
370 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
372 GObjectClass *gobject_class;
373 HildonWindowClass *hildon_window_class;
374 ModestWindowClass *modest_window_class;
375 GtkBindingSet *binding_set;
377 gobject_class = (GObjectClass*) klass;
378 hildon_window_class = (HildonWindowClass *) klass;
379 modest_window_class = (ModestWindowClass *) klass;
381 parent_class = g_type_class_peek_parent (klass);
382 gobject_class->finalize = modest_msg_view_window_finalize;
384 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
385 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
386 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
387 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
388 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
389 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
391 modest_window_class->save_state_func = save_state;
393 klass->scroll_child = modest_msg_view_window_scroll_child;
395 signals[MSG_CHANGED_SIGNAL] =
396 g_signal_new ("msg-changed",
397 G_TYPE_FROM_CLASS (gobject_class),
399 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
401 modest_marshal_VOID__POINTER_POINTER,
402 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
404 signals[SCROLL_CHILD_SIGNAL] =
405 g_signal_new ("scroll-child",
406 G_TYPE_FROM_CLASS (gobject_class),
407 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
408 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
410 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
411 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
413 binding_set = gtk_binding_set_by_class (klass);
414 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
415 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
416 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
417 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
418 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
419 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
421 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
425 static void modest_header_view_observer_init(
426 ModestHeaderViewObserverIface *iface_class)
428 iface_class->update_func = modest_msg_view_window_update_model_replaced;
432 modest_msg_view_window_init (ModestMsgViewWindow *obj)
434 ModestMsgViewWindowPrivate *priv;
435 ModestWindowPrivate *parent_priv = NULL;
436 GtkActionGroup *action_group = NULL;
437 GError *error = NULL;
439 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
440 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
441 parent_priv->ui_manager = gtk_ui_manager_new();
443 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
444 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
446 /* Add common actions */
447 gtk_action_group_add_actions (action_group,
448 modest_action_entries,
449 G_N_ELEMENTS (modest_action_entries),
451 gtk_action_group_add_toggle_actions (action_group,
452 msg_view_toggle_action_entries,
453 G_N_ELEMENTS (msg_view_toggle_action_entries),
456 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
457 g_object_unref (action_group);
459 /* Load the UI definition */
460 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
463 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
464 g_error_free (error);
469 /* Add accelerators */
470 gtk_window_add_accel_group (GTK_WINDOW (obj),
471 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
473 priv->is_search_result = FALSE;
474 priv->is_outbox = FALSE;
476 priv->msg_view = NULL;
477 priv->header_model = NULL;
478 priv->header_folder_id = NULL;
479 priv->clipboard_change_handler = 0;
480 priv->queue_change_handler = 0;
481 priv->account_removed_handler = 0;
482 priv->row_changed_handler = 0;
483 priv->row_deleted_handler = 0;
484 priv->row_inserted_handler = 0;
485 priv->rows_reordered_handler = 0;
486 priv->fetch_image_redraw_handler = 0;
487 priv->progress_hint = FALSE;
488 priv->fetching_images = 0;
490 priv->optimized_view = FALSE;
491 priv->purge_timeout = 0;
492 priv->remove_attachment_banner = NULL;
493 priv->msg_uid = NULL;
494 priv->other_body = NULL;
496 priv->sighandlers = NULL;
499 init_window (MODEST_MSG_VIEW_WINDOW(obj));
501 hildon_program_add_window (hildon_program_get_instance(),
504 /* Grab the zoom keys, it will be used for Zoom and not for
506 g_signal_connect (G_OBJECT (obj), "realize",
507 G_CALLBACK (on_realize),
512 update_progress_hint (ModestMsgViewWindow *self)
514 ModestMsgViewWindowPrivate *priv;
515 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
517 if (GTK_WIDGET_VISIBLE (self)) {
518 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self),
519 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
524 set_progress_hint (ModestMsgViewWindow *self,
527 ModestWindowPrivate *parent_priv;
528 ModestMsgViewWindowPrivate *priv;
530 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
532 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
535 /* Sets current progress hint */
536 priv->progress_hint = enabled;
538 update_progress_hint (self);
544 init_window (ModestMsgViewWindow *obj)
546 GtkWidget *main_vbox;
547 ModestMsgViewWindowPrivate *priv;
549 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
551 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
552 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
553 main_vbox = gtk_vbox_new (FALSE, 6);
554 priv->main_scroll = hildon_pannable_area_new ();
555 g_object_set (G_OBJECT (priv->main_scroll),
556 "mov-mode", HILDON_MOVEMENT_MODE_BOTH,
559 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
560 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
561 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
563 /* NULL-ize fields if the window is destroyed */
564 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
566 gtk_widget_show_all (GTK_WIDGET(main_vbox));
570 modest_msg_view_window_disconnect_signals (ModestWindow *self)
572 ModestMsgViewWindowPrivate *priv;
573 GtkWidget *header_view = NULL;
574 GtkWindow *parent_window = NULL;
576 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
578 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
579 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
580 priv->clipboard_change_handler))
581 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
582 priv->clipboard_change_handler);
584 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
585 priv->queue_change_handler))
586 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
587 priv->queue_change_handler);
589 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
590 priv->account_removed_handler))
591 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
592 priv->account_removed_handler);
594 if (priv->header_model) {
595 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
596 priv->row_changed_handler))
597 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
598 priv->row_changed_handler);
600 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
601 priv->row_deleted_handler))
602 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
603 priv->row_deleted_handler);
605 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
606 priv->row_inserted_handler))
607 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
608 priv->row_inserted_handler);
610 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
611 priv->rows_reordered_handler))
612 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
613 priv->rows_reordered_handler);
616 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
617 priv->sighandlers = NULL;
619 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
620 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
621 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
623 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
624 MODEST_HEADER_VIEW_OBSERVER(self));
630 modest_msg_view_window_finalize (GObject *obj)
632 ModestMsgViewWindowPrivate *priv;
634 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
636 /* Sanity check: shouldn't be needed, the window mgr should
637 call this function before */
638 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
640 if (priv->fetch_image_redraw_handler > 0) {
641 g_source_remove (priv->fetch_image_redraw_handler);
642 priv->fetch_image_redraw_handler = 0;
645 if (priv->other_body != NULL) {
646 g_object_unref (priv->other_body);
647 priv->other_body = NULL;
650 if (priv->top_msg != NULL) {
651 g_object_unref (priv->top_msg);
652 priv->top_msg = NULL;
655 if (priv->header_model != NULL) {
656 g_object_unref (priv->header_model);
657 priv->header_model = NULL;
660 if (priv->remove_attachment_banner) {
661 gtk_widget_destroy (priv->remove_attachment_banner);
662 g_object_unref (priv->remove_attachment_banner);
663 priv->remove_attachment_banner = NULL;
666 if (priv->purge_timeout > 0) {
667 g_source_remove (priv->purge_timeout);
668 priv->purge_timeout = 0;
671 if (priv->row_reference) {
672 gtk_tree_row_reference_free (priv->row_reference);
673 priv->row_reference = NULL;
676 if (priv->next_row_reference) {
677 gtk_tree_row_reference_free (priv->next_row_reference);
678 priv->next_row_reference = NULL;
682 g_free (priv->msg_uid);
683 priv->msg_uid = NULL;
686 G_OBJECT_CLASS(parent_class)->finalize (obj);
690 select_next_valid_row (GtkTreeModel *model,
691 GtkTreeRowReference **row_reference,
695 GtkTreeIter tmp_iter;
697 GtkTreePath *next = NULL;
698 gboolean retval = FALSE, finished;
700 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
702 path = gtk_tree_row_reference_get_path (*row_reference);
703 gtk_tree_model_get_iter (model, &tmp_iter, path);
704 gtk_tree_row_reference_free (*row_reference);
705 *row_reference = NULL;
709 TnyHeader *header = NULL;
711 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
712 gtk_tree_model_get (model, &tmp_iter,
713 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
717 if (msg_is_visible (header, is_outbox)) {
718 next = gtk_tree_model_get_path (model, &tmp_iter);
719 *row_reference = gtk_tree_row_reference_new (model, next);
720 gtk_tree_path_free (next);
724 g_object_unref (header);
727 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
728 next = gtk_tree_model_get_path (model, &tmp_iter);
730 /* Ensure that we are not selecting the same */
731 if (gtk_tree_path_compare (path, next) != 0) {
732 gtk_tree_model_get (model, &tmp_iter,
733 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
736 if (msg_is_visible (header, is_outbox)) {
737 *row_reference = gtk_tree_row_reference_new (model, next);
741 g_object_unref (header);
745 /* If we ended up in the same message
746 then there is no valid next
750 gtk_tree_path_free (next);
752 /* If there are no more messages and we don't
753 want to start again in the first one then
754 there is no valid next message */
760 gtk_tree_path_free (path);
765 /* TODO: This should be in _init(), with the parameters as properties. */
767 modest_msg_view_window_construct (ModestMsgViewWindow *self,
768 const gchar *modest_account_name,
769 const gchar *mailbox,
770 const gchar *msg_uid)
773 ModestMsgViewWindowPrivate *priv = NULL;
774 ModestWindowPrivate *parent_priv = NULL;
775 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
776 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
778 obj = G_OBJECT (self);
779 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
780 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
782 priv->msg_uid = g_strdup (msg_uid);
785 parent_priv->menubar = NULL;
787 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
788 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
791 /* Add common dimming rules */
792 modest_dimming_rules_group_add_rules (toolbar_rules_group,
793 modest_msg_view_toolbar_dimming_entries,
794 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
795 MODEST_WINDOW (self));
796 modest_dimming_rules_group_add_rules (clipboard_rules_group,
797 modest_msg_view_clipboard_dimming_entries,
798 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
799 MODEST_WINDOW (self));
801 /* Insert dimming rules group for this window */
802 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
803 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
804 g_object_unref (toolbar_rules_group);
805 g_object_unref (clipboard_rules_group);
807 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
809 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
810 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
811 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
812 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
813 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
814 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
815 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
816 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
817 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
818 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
819 G_CALLBACK (modest_ui_actions_on_details), obj);
820 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
821 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
822 g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
823 G_CALLBACK (modest_ui_actions_on_limit_error), obj);
824 g_signal_connect (G_OBJECT(priv->msg_view), "handle_calendar",
825 G_CALLBACK (on_handle_calendar), obj);
826 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
827 G_CALLBACK (on_fetch_image), obj);
829 g_signal_connect (G_OBJECT (obj), "key-release-event",
830 G_CALLBACK (modest_msg_view_window_key_event),
833 g_signal_connect (G_OBJECT (obj), "key-press-event",
834 G_CALLBACK (modest_msg_view_window_key_event),
837 g_signal_connect (G_OBJECT (obj), "move-focus",
838 G_CALLBACK (on_move_focus), obj);
840 g_signal_connect (G_OBJECT (obj), "map-event",
841 G_CALLBACK (_modest_msg_view_window_map_event),
844 /* Mail Operation Queue */
845 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
847 G_CALLBACK (on_queue_changed),
850 /* Account manager */
851 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
853 G_CALLBACK(on_account_removed),
856 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
857 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
859 /* First add out toolbar ... */
860 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
862 /* ... and later the find toolbar. This way find toolbar will
863 be shown over the other */
864 priv->find_toolbar = hildon_find_toolbar_new (NULL);
865 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
866 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
867 g_signal_connect (G_OBJECT (priv->find_toolbar), "close",
868 G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
869 g_signal_connect (G_OBJECT (priv->find_toolbar), "search",
870 G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
871 priv->last_search = NULL;
873 /* Init the clipboard actions dim status */
874 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
876 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
881 /* FIXME: parameter checks */
883 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
884 const gchar *modest_account_name,
885 const gchar *mailbox,
886 const gchar *msg_uid,
888 GtkTreeRowReference *row_reference)
890 ModestMsgViewWindow *window = NULL;
891 ModestMsgViewWindowPrivate *priv = NULL;
892 TnyFolder *header_folder = NULL;
893 ModestHeaderView *header_view = NULL;
894 ModestWindowMgr *mgr = NULL;
897 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
900 mgr = modest_runtime_get_window_mgr ();
901 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
902 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
904 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
906 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
907 priv->top_msg = NULL;
909 /* Remember the message list's TreeModel so we can detect changes
910 * and change the list selection when necessary: */
911 header_folder = modest_header_view_get_folder (header_view);
913 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
914 TNY_FOLDER_TYPE_OUTBOX);
915 priv->header_folder_id = tny_folder_get_id (header_folder);
916 g_object_unref(header_folder);
919 /* Setup row references and connect signals */
920 priv->header_model = g_object_ref (model);
922 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
923 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
924 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
925 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
927 priv->row_reference = NULL;
928 priv->next_row_reference = NULL;
931 /* Connect signals */
932 priv->row_changed_handler =
933 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
934 G_CALLBACK(modest_msg_view_window_on_row_changed),
936 priv->row_deleted_handler =
937 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
938 G_CALLBACK(modest_msg_view_window_on_row_deleted),
940 priv->row_inserted_handler =
941 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
942 G_CALLBACK(modest_msg_view_window_on_row_inserted),
944 priv->rows_reordered_handler =
945 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
946 G_CALLBACK(modest_msg_view_window_on_row_reordered),
949 if (header_view != NULL){
950 modest_header_view_add_observer(header_view,
951 MODEST_HEADER_VIEW_OBSERVER(window));
954 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
955 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
956 update_branding (MODEST_MSG_VIEW_WINDOW (window));
958 /* gtk_widget_show_all (GTK_WIDGET (window)); */
959 modest_msg_view_window_update_priority (window);
960 /* Check dimming rules */
961 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
962 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
963 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
965 return MODEST_WINDOW(window);
969 modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
970 const gchar *mailbox,
971 const gchar *msg_uid)
973 ModestMsgViewWindow *window = NULL;
974 ModestMsgViewWindowPrivate *priv = NULL;
975 ModestWindowMgr *mgr = NULL;
977 TnyAccount *account = NULL;
979 mgr = modest_runtime_get_window_mgr ();
980 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
981 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
983 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
985 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
986 priv->top_msg = NULL;
988 is_merge = g_str_has_prefix (msg_uid, "merge:");
990 /* Get the account */
992 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
995 if (is_merge || account) {
996 TnyFolder *folder = NULL;
998 /* Try to get the message, if it's already downloaded
999 we don't need to connect */
1001 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
1003 ModestTnyAccountStore *account_store;
1004 ModestTnyLocalFoldersAccount *local_folders_account;
1006 account_store = modest_runtime_get_account_store ();
1007 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
1008 modest_tny_account_store_get_local_folders_account (account_store));
1009 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
1010 g_object_unref (local_folders_account);
1014 gboolean device_online;
1016 device = modest_runtime_get_device();
1017 device_online = tny_device_is_online (device);
1018 if (device_online) {
1019 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1021 TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
1023 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1024 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
1025 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1026 g_object_unref (msg);
1027 /* Sync flags to server */
1028 sync_flags (MODEST_MSG_VIEW_WINDOW (window));
1030 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1033 g_object_unref (folder);
1038 /* Check dimming rules */
1039 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1040 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1041 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1043 return MODEST_WINDOW(window);
1047 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1048 const gchar *modest_account_name,
1049 const gchar *mailbox,
1050 const gchar *msg_uid,
1051 GtkTreeRowReference *row_reference)
1053 ModestMsgViewWindow *window = NULL;
1054 ModestMsgViewWindowPrivate *priv = NULL;
1055 TnyFolder *header_folder = NULL;
1056 ModestWindowMgr *mgr = NULL;
1060 mgr = modest_runtime_get_window_mgr ();
1061 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1062 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1064 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1066 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1067 priv->top_msg = NULL;
1069 /* Remember the message list's TreeModel so we can detect changes
1070 * and change the list selection when necessary: */
1072 if (header_view != NULL){
1073 header_folder = modest_header_view_get_folder(header_view);
1074 /* This could happen if the header folder was
1075 unseleted before opening this msg window (for
1076 example if the user selects an account in the
1077 folder view of the main window */
1078 if (header_folder) {
1079 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1080 TNY_FOLDER_TYPE_OUTBOX);
1081 priv->header_folder_id = tny_folder_get_id(header_folder);
1082 g_object_unref(header_folder);
1086 /* Setup row references and connect signals */
1087 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1088 g_object_ref (priv->header_model);
1090 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
1091 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1092 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1093 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1095 priv->row_reference = NULL;
1096 priv->next_row_reference = NULL;
1099 /* Connect signals */
1100 priv->row_changed_handler =
1101 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1102 G_CALLBACK(modest_msg_view_window_on_row_changed),
1104 priv->row_deleted_handler =
1105 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1106 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1108 priv->row_inserted_handler =
1109 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1110 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1112 priv->rows_reordered_handler =
1113 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1114 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1117 if (header_view != NULL){
1118 modest_header_view_add_observer(header_view,
1119 MODEST_HEADER_VIEW_OBSERVER(window));
1122 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1123 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1125 if (priv->row_reference) {
1126 path = gtk_tree_row_reference_get_path (priv->row_reference);
1127 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1129 gtk_tree_model_get (priv->header_model, &iter,
1130 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1132 message_reader (window, priv, header, NULL, NULL, priv->row_reference);
1133 g_object_unref (header);
1135 gtk_tree_path_free (path);
1137 /* Check dimming rules */
1138 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1139 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1140 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1142 return MODEST_WINDOW(window);
1146 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1147 const gchar *modest_account_name,
1148 const gchar *mailbox,
1149 const gchar *msg_uid)
1151 ModestMsgViewWindow *window = NULL;
1152 ModestMsgViewWindowPrivate *priv = NULL;
1153 ModestWindowMgr *mgr = NULL;
1155 mgr = modest_runtime_get_window_mgr ();
1156 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1157 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1158 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1160 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1161 priv->top_msg = NULL;
1163 /* Remember that this is a search result,
1164 * so we can disable some UI appropriately: */
1165 priv->is_search_result = TRUE;
1167 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1168 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1170 update_window_title (window);
1171 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1172 modest_msg_view_window_update_priority (window);
1174 /* Check dimming rules */
1175 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1176 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1177 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1179 return MODEST_WINDOW(window);
1183 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1185 ModestMsgViewWindowPrivate *priv = NULL;
1187 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1188 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1190 return (priv->other_body != NULL);
1194 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1195 TnyMimePart *other_body,
1197 const gchar *modest_account_name,
1198 const gchar *mailbox,
1199 const gchar *msg_uid)
1201 GObject *obj = NULL;
1202 ModestMsgViewWindowPrivate *priv;
1203 ModestWindowMgr *mgr = NULL;
1205 g_return_val_if_fail (msg, NULL);
1206 mgr = modest_runtime_get_window_mgr ();
1207 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1208 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1209 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1210 modest_account_name, mailbox, msg_uid);
1213 priv->other_body = g_object_ref (other_body);
1214 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1216 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1219 priv->top_msg = g_object_ref (top_msg);
1221 priv->top_msg = NULL;
1223 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1224 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1226 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1228 /* Check dimming rules */
1229 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1230 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1231 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1233 return MODEST_WINDOW(obj);
1237 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1239 const gchar *modest_account_name,
1240 const gchar *mailbox,
1241 const gchar *msg_uid)
1243 return modest_msg_view_window_new_with_other_body (msg, NULL, top_msg, modest_account_name, mailbox, msg_uid);
1247 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1250 ModestMsgViewWindow *window)
1252 check_dimming_rules_after_change (window);
1256 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1258 ModestMsgViewWindow *window)
1260 check_dimming_rules_after_change (window);
1262 /* The window could have dissapeared */
1265 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1267 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1268 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1272 /* On insertions we check if the folder still has the message we are
1273 * showing or do not. If do not, we do nothing. Which means we are still
1274 * not attached to any header folder and thus next/prev buttons are
1275 * still dimmed. Once the message that is shown by msg-view is found, the
1276 * new model of header-view will be attached and the references will be set.
1277 * On each further insertions dimming rules will be checked. However
1278 * this requires extra CPU time at least works.
1279 * (An message might be deleted from TnyFolder and thus will not be
1280 * inserted into the model again for example if it is removed by the
1281 * imap server and the header view is refreshed.)
1284 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1285 GtkTreePath *tree_path,
1286 GtkTreeIter *tree_iter,
1287 ModestMsgViewWindow *window)
1289 ModestMsgViewWindowPrivate *priv = NULL;
1290 TnyHeader *header = NULL;
1292 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1293 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1295 g_assert (model == priv->header_model);
1297 /* Check if the newly inserted message is the same we are actually
1298 * showing. IF not, we should remain detached from the header model
1299 * and thus prev and next toolbar buttons should remain dimmed. */
1300 gtk_tree_model_get (model, tree_iter,
1301 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1304 if (TNY_IS_HEADER (header)) {
1307 uid = modest_tny_folder_get_header_unique_id (header);
1308 if (!g_str_equal(priv->msg_uid, uid)) {
1309 check_dimming_rules_after_change (window);
1311 g_object_unref (G_OBJECT(header));
1315 g_object_unref(G_OBJECT(header));
1318 if (priv->row_reference) {
1319 gtk_tree_row_reference_free (priv->row_reference);
1322 /* Setup row_reference for the actual msg. */
1323 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1324 if (priv->row_reference == NULL) {
1325 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1329 /* Now set up next_row_reference. */
1330 if (priv->next_row_reference) {
1331 gtk_tree_row_reference_free (priv->next_row_reference);
1334 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1335 select_next_valid_row (priv->header_model,
1336 &(priv->next_row_reference), FALSE, priv->is_outbox);
1338 /* Connect the remaining callbacks to become able to detect
1339 * changes in header-view. */
1340 priv->row_changed_handler =
1341 g_signal_connect (priv->header_model, "row-changed",
1342 G_CALLBACK (modest_msg_view_window_on_row_changed),
1344 priv->row_deleted_handler =
1345 g_signal_connect (priv->header_model, "row-deleted",
1346 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1348 priv->rows_reordered_handler =
1349 g_signal_connect (priv->header_model, "rows-reordered",
1350 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1353 check_dimming_rules_after_change (window);
1357 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1361 ModestMsgViewWindow *window)
1363 ModestMsgViewWindowPrivate *priv = NULL;
1364 gboolean already_changed = FALSE;
1366 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1368 /* If the current row was reordered select the proper next
1369 valid row. The same if the next row reference changes */
1370 if (!priv->row_reference ||
1371 !gtk_tree_row_reference_valid (priv->row_reference))
1374 if (priv->next_row_reference &&
1375 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1376 GtkTreePath *cur, *next;
1377 /* Check that the order is still the correct one */
1378 cur = gtk_tree_row_reference_get_path (priv->row_reference);
1379 next = gtk_tree_row_reference_get_path (priv->next_row_reference);
1380 gtk_tree_path_next (cur);
1381 if (gtk_tree_path_compare (cur, next) != 0) {
1382 gtk_tree_row_reference_free (priv->next_row_reference);
1383 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1384 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1385 already_changed = TRUE;
1387 gtk_tree_path_free (cur);
1388 gtk_tree_path_free (next);
1390 if (priv->next_row_reference)
1391 gtk_tree_row_reference_free (priv->next_row_reference);
1392 /* Update next row reference */
1393 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1394 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1395 already_changed = TRUE;
1398 check_dimming_rules_after_change (window);
1401 /* The modest_msg_view_window_update_model_replaced implements update
1402 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1403 * actually belongs to the header-view is the same as the TnyFolder of
1404 * the message of msg-view or not. If they are different, there is
1405 * nothing to do. If they are the same, then the model has replaced and
1406 * the reference in msg-view shall be replaced from the old model to
1407 * the new model. In this case the view will be detached from it's
1408 * header folder. From this point the next/prev buttons are dimmed.
1411 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1412 GtkTreeModel *model,
1413 const gchar *tny_folder_id)
1415 ModestMsgViewWindowPrivate *priv = NULL;
1416 ModestMsgViewWindow *window = NULL;
1418 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1419 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1421 window = MODEST_MSG_VIEW_WINDOW(observer);
1422 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1424 /* If there is an other folder in the header-view then we do
1425 * not care about it's model (msg list). Else if the
1426 * header-view shows the folder the msg shown by us is in, we
1427 * shall replace our model reference and make some check. */
1428 if(model == NULL || tny_folder_id == NULL ||
1429 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1432 /* Model is changed(replaced), so we should forget the old
1433 * one. Because there might be other references and there
1434 * might be some change on the model even if we unreferenced
1435 * it, we need to disconnect our signals here. */
1436 if (priv->header_model) {
1437 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1438 priv->row_changed_handler))
1439 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1440 priv->row_changed_handler);
1441 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1442 priv->row_deleted_handler))
1443 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1444 priv->row_deleted_handler);
1445 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1446 priv->row_inserted_handler))
1447 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1448 priv->row_inserted_handler);
1449 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1450 priv->rows_reordered_handler))
1451 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1452 priv->rows_reordered_handler);
1455 if (priv->row_reference)
1456 gtk_tree_row_reference_free (priv->row_reference);
1457 if (priv->next_row_reference)
1458 gtk_tree_row_reference_free (priv->next_row_reference);
1459 g_object_unref(priv->header_model);
1462 priv->row_changed_handler = 0;
1463 priv->row_deleted_handler = 0;
1464 priv->row_inserted_handler = 0;
1465 priv->rows_reordered_handler = 0;
1466 priv->next_row_reference = NULL;
1467 priv->row_reference = NULL;
1468 priv->header_model = NULL;
1471 priv->header_model = g_object_ref (model);
1473 /* Also we must connect to the new model for row insertions.
1474 * Only for insertions now. We will need other ones only after
1475 * the msg is show by msg-view is added to the new model. */
1476 priv->row_inserted_handler =
1477 g_signal_connect (priv->header_model, "row-inserted",
1478 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1481 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1482 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1486 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1488 ModestMsgViewWindowPrivate *priv= NULL;
1490 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1491 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1493 return priv->progress_hint;
1497 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1499 ModestMsgViewWindowPrivate *priv= NULL;
1501 TnyHeader *header = NULL;
1502 GtkTreePath *path = NULL;
1505 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1506 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1508 /* If the message was not obtained from a treemodel,
1509 * for instance if it was opened directly by the search UI:
1511 if (priv->header_model == NULL ||
1512 priv->row_reference == NULL ||
1513 !gtk_tree_row_reference_valid (priv->row_reference)) {
1514 msg = modest_msg_view_window_get_message (self);
1516 header = tny_msg_get_header (msg);
1517 g_object_unref (msg);
1522 /* Get iter of the currently selected message in the header view: */
1523 path = gtk_tree_row_reference_get_path (priv->row_reference);
1524 g_return_val_if_fail (path != NULL, NULL);
1525 gtk_tree_model_get_iter (priv->header_model,
1529 /* Get current message header */
1530 gtk_tree_model_get (priv->header_model, &iter,
1531 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1534 gtk_tree_path_free (path);
1539 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1541 ModestMsgViewWindowPrivate *priv;
1543 g_return_val_if_fail (self, NULL);
1545 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1547 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1551 modest_msg_view_window_get_top_message (ModestMsgViewWindow *self)
1553 ModestMsgViewWindowPrivate *priv;
1555 g_return_val_if_fail (self, NULL);
1557 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1560 return g_object_ref (priv->top_msg);
1566 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1568 ModestMsgViewWindowPrivate *priv;
1570 g_return_val_if_fail (self, NULL);
1572 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1574 return (const gchar*) priv->msg_uid;
1577 /* Used for the Ctrl+F accelerator */
1579 modest_msg_view_window_toggle_find_toolbar (GtkWidget *obj,
1582 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1583 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1585 if (GTK_WIDGET_VISIBLE (priv->find_toolbar)) {
1586 modest_msg_view_window_find_toolbar_close (obj, data);
1588 modest_msg_view_window_show_find_toolbar (obj, data);
1592 /* Handler for menu option */
1594 modest_msg_view_window_show_find_toolbar (GtkWidget *obj,
1597 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1598 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1600 gtk_widget_show (priv->find_toolbar);
1601 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1604 /* Handler for click on the "X" close button in find toolbar */
1606 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1607 ModestMsgViewWindow *obj)
1609 ModestMsgViewWindowPrivate *priv;
1611 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1614 gtk_widget_hide (priv->find_toolbar);
1615 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1619 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1620 ModestMsgViewWindow *obj)
1622 gchar *current_search;
1623 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1625 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1626 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1630 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1632 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1633 g_free (current_search);
1634 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
1638 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1640 g_free (priv->last_search);
1641 priv->last_search = g_strdup (current_search);
1642 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1645 hildon_banner_show_information (NULL, NULL,
1646 _HL("ckct_ib_find_no_matches"));
1647 g_free (priv->last_search);
1648 priv->last_search = NULL;
1650 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1653 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1654 hildon_banner_show_information (NULL, NULL,
1655 _HL("ckct_ib_find_search_complete"));
1656 g_free (priv->last_search);
1657 priv->last_search = NULL;
1659 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1663 g_free (current_search);
1668 modest_msg_view_window_set_zoom (ModestWindow *window,
1671 ModestMsgViewWindowPrivate *priv;
1672 ModestWindowPrivate *parent_priv;
1674 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1676 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1677 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1678 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1683 modest_msg_view_window_get_zoom (ModestWindow *window)
1685 ModestMsgViewWindowPrivate *priv;
1687 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1689 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1690 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1694 modest_msg_view_window_zoom_plus (ModestWindow *window)
1697 ModestMsgViewWindowPrivate *priv;
1701 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1702 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1704 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1706 if (zoom_level >= 2.0) {
1707 hildon_banner_show_information (NULL, NULL,
1708 _CS("ckct_ib_max_zoom_level_reached"));
1710 } else if (zoom_level >= 1.5) {
1712 } else if (zoom_level >= 1.2) {
1714 } else if (zoom_level >= 1.0) {
1716 } else if (zoom_level >= 0.8) {
1718 } else if (zoom_level >= 0.5) {
1724 /* set zoom level */
1725 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1726 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1727 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1728 g_free (banner_text);
1729 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1735 modest_msg_view_window_zoom_minus (ModestWindow *window)
1738 ModestMsgViewWindowPrivate *priv;
1742 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1743 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1745 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1747 if (zoom_level <= 0.5) {
1748 hildon_banner_show_information (NULL, NULL,
1749 _CS("ckct_ib_min_zoom_level_reached"));
1751 } else if (zoom_level <= 0.8) {
1753 } else if (zoom_level <= 1.0) {
1755 } else if (zoom_level <= 1.2) {
1757 } else if (zoom_level <= 1.5) {
1759 } else if (zoom_level <= 2.0) {
1765 /* set zoom level */
1766 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1767 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1768 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1769 g_free (banner_text);
1770 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1776 modest_msg_view_window_key_event (GtkWidget *window,
1782 focus = gtk_window_get_focus (GTK_WINDOW (window));
1784 /* for the find toolbar case */
1785 if (focus && GTK_IS_ENTRY (focus)) {
1786 if (event->keyval == GDK_BackSpace) {
1788 copy = gdk_event_copy ((GdkEvent *) event);
1789 gtk_widget_event (focus, copy);
1790 gdk_event_free (copy);
1800 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1803 ModestMsgViewWindowPrivate *priv;
1804 GtkTreeIter tmp_iter;
1805 gboolean is_last_selected;
1807 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1808 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1810 /*if no model (so no rows at all), then virtually we are the last*/
1811 if (!priv->header_model || !priv->row_reference)
1814 if (!gtk_tree_row_reference_valid (priv->row_reference))
1817 path = gtk_tree_row_reference_get_path (priv->row_reference);
1821 is_last_selected = TRUE;
1822 while (is_last_selected) {
1824 gtk_tree_path_next (path);
1825 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1827 gtk_tree_model_get (priv->header_model, &tmp_iter,
1828 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1831 if (msg_is_visible (header, priv->is_outbox))
1832 is_last_selected = FALSE;
1833 g_object_unref(G_OBJECT(header));
1836 gtk_tree_path_free (path);
1837 return is_last_selected;
1841 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1843 ModestMsgViewWindowPrivate *priv;
1845 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1846 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1848 return priv->header_model != NULL;
1852 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1854 ModestMsgViewWindowPrivate *priv;
1856 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1857 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1859 return priv->is_search_result;
1863 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1865 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1867 if (!check_outbox) {
1870 ModestTnySendQueueStatus status;
1871 status = modest_tny_all_send_queues_get_msg_status (header);
1872 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1873 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1878 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1881 ModestMsgViewWindowPrivate *priv;
1882 gboolean is_first_selected;
1883 GtkTreeIter tmp_iter;
1885 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1886 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1888 /*if no model (so no rows at all), then virtually we are the first*/
1889 if (!priv->header_model || !priv->row_reference)
1892 if (!gtk_tree_row_reference_valid (priv->row_reference))
1895 path = gtk_tree_row_reference_get_path (priv->row_reference);
1899 is_first_selected = TRUE;
1900 while (is_first_selected) {
1902 if(!gtk_tree_path_prev (path))
1904 /* Here the 'if' is needless for logic, but let make sure
1905 * iter is valid for gtk_tree_model_get. */
1906 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1908 gtk_tree_model_get (priv->header_model, &tmp_iter,
1909 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1912 if (msg_is_visible (header, priv->is_outbox))
1913 is_first_selected = FALSE;
1914 g_object_unref(G_OBJECT(header));
1917 gtk_tree_path_free (path);
1918 return is_first_selected;
1925 GtkTreeRowReference *row_reference;
1929 message_reader_performer (gboolean canceled,
1931 GtkWindow *parent_window,
1932 TnyAccount *account,
1935 ModestMailOperation *mail_op = NULL;
1936 MsgReaderInfo *info;
1938 info = (MsgReaderInfo *) user_data;
1939 if (canceled || err) {
1940 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1941 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (parent_window));
1945 /* Register the header - it'll be unregistered in the callback */
1947 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1949 /* New mail operation */
1950 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1951 modest_ui_actions_disk_operations_error_handler,
1954 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1956 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1958 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1959 g_object_unref (mail_op);
1961 /* Update dimming rules */
1962 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1963 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1966 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1967 g_free (info->msg_uid);
1969 g_object_unref (info->folder);
1971 g_object_unref (info->header);
1972 g_slice_free (MsgReaderInfo, info);
1977 * Reads the message whose summary item is @header. It takes care of
1978 * several things, among others:
1980 * If the message was not previously downloaded then ask the user
1981 * before downloading. If there is no connection launch the connection
1982 * dialog. Update toolbar dimming rules.
1984 * Returns: TRUE if the mail operation was started, otherwise if the
1985 * user do not want to download the message, or if the user do not
1986 * want to connect, then the operation is not issued
1989 message_reader (ModestMsgViewWindow *window,
1990 ModestMsgViewWindowPrivate *priv,
1992 const gchar *msg_uid,
1994 GtkTreeRowReference *row_reference)
1996 ModestWindowMgr *mgr;
1997 TnyAccount *account = NULL;
1998 MsgReaderInfo *info;
2000 /* We set the header from model while we're loading */
2001 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
2002 gtk_window_set_title (GTK_WINDOW (window), _CS("ckdg_pb_updating"));
2008 g_object_ref (folder);
2010 mgr = modest_runtime_get_window_mgr ();
2011 /* Msg download completed */
2012 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
2014 /* Ask the user if he wants to download the message if
2016 if (!tny_device_is_online (modest_runtime_get_device())) {
2017 GtkResponseType response;
2019 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2020 _("mcen_nc_get_msg"));
2021 if (response == GTK_RESPONSE_CANCEL) {
2022 update_window_title (window);
2027 folder = tny_header_get_folder (header);
2029 info = g_slice_new (MsgReaderInfo);
2030 info->msg_uid = g_strdup (msg_uid);
2032 info->header = g_object_ref (header);
2034 info->header = NULL;
2036 info->folder = g_object_ref (folder);
2038 info->folder = NULL;
2039 if (row_reference) {
2040 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2042 info->row_reference = NULL;
2045 /* Offer the connection dialog if necessary */
2046 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
2048 TNY_FOLDER_STORE (folder),
2049 message_reader_performer,
2052 g_object_unref (folder);
2058 folder = tny_header_get_folder (header);
2061 account = tny_folder_get_account (folder);
2063 info = g_slice_new (MsgReaderInfo);
2064 info->msg_uid = g_strdup (msg_uid);
2066 info->folder = g_object_ref (folder);
2068 info->folder = NULL;
2070 info->header = g_object_ref (header);
2072 info->header = NULL;
2074 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2076 info->row_reference = NULL;
2078 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
2080 g_object_unref (account);
2082 g_object_unref (folder);
2088 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2090 ModestMsgViewWindowPrivate *priv;
2091 GtkTreePath *path= NULL;
2092 GtkTreeIter tmp_iter;
2094 gboolean retval = TRUE;
2095 GtkTreeRowReference *row_reference = NULL;
2097 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2098 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2100 if (!priv->row_reference)
2103 /* Update the next row reference if it's not valid. This could
2104 happen if for example the header which it was pointing to,
2105 was deleted. The best place to do it is in the row-deleted
2106 handler but the tinymail model do not work like the glib
2107 tree models and reports the deletion when the row is still
2109 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2110 if (priv->next_row_reference) {
2111 gtk_tree_row_reference_free (priv->next_row_reference);
2113 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2114 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2115 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2117 priv->next_row_reference = NULL;
2120 if (priv->next_row_reference)
2121 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2125 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2127 gtk_tree_model_get_iter (priv->header_model,
2130 gtk_tree_path_free (path);
2132 gtk_tree_model_get (priv->header_model, &tmp_iter,
2133 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2136 /* Read the message & show it */
2137 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2140 gtk_tree_row_reference_free (row_reference);
2143 g_object_unref (header);
2149 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2151 ModestMsgViewWindowPrivate *priv = NULL;
2153 gboolean finished = FALSE;
2154 gboolean retval = FALSE;
2156 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2157 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2159 if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
2160 gtk_tree_row_reference_free (priv->row_reference);
2161 priv->row_reference = NULL;
2164 /* Return inmediatly if there is no header model */
2165 if (!priv->header_model || !priv->row_reference)
2168 path = gtk_tree_row_reference_get_path (priv->row_reference);
2169 while (!finished && gtk_tree_path_prev (path)) {
2173 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2174 gtk_tree_model_get (priv->header_model, &iter,
2175 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2179 if (msg_is_visible (header, priv->is_outbox)) {
2180 GtkTreeRowReference *row_reference;
2181 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2182 /* Read the message & show it */
2183 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2184 gtk_tree_row_reference_free (row_reference);
2188 g_object_unref (header);
2192 gtk_tree_path_free (path);
2197 view_msg_cb (ModestMailOperation *mail_op,
2204 ModestMsgViewWindow *self = NULL;
2205 ModestMsgViewWindowPrivate *priv = NULL;
2206 GtkTreeRowReference *row_reference = NULL;
2208 /* Unregister the header (it was registered before creating the mail operation) */
2209 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2211 row_reference = (GtkTreeRowReference *) user_data;
2214 gtk_tree_row_reference_free (row_reference);
2215 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2217 /* Restore window title */
2218 update_window_title (self);
2219 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2220 g_object_unref (self);
2225 /* If there was any error */
2226 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2228 gtk_tree_row_reference_free (row_reference);
2229 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2231 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2232 /* First we check if the parent is a folder window */
2233 if (priv->msg_uid && !modest_hildon2_window_mgr_get_folder_window (MODEST_HILDON2_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2235 TnyAccount *account = NULL;
2236 GtkWidget *header_window = NULL;
2238 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2240 /* Get the account */
2242 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2245 if (is_merge || account) {
2246 TnyFolder *folder = NULL;
2248 /* Try to get the message, if it's already downloaded
2249 we don't need to connect */
2251 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2254 ModestTnyAccountStore *account_store;
2255 ModestTnyLocalFoldersAccount *local_folders_account;
2257 account_store = modest_runtime_get_account_store ();
2258 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2259 modest_tny_account_store_get_local_folders_account (account_store));
2260 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2261 g_object_unref (local_folders_account);
2263 if (account) g_object_unref (account);
2266 header_window = (GtkWidget *)
2267 modest_header_window_new (
2269 modest_window_get_active_account (MODEST_WINDOW (self)),
2270 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2271 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2272 MODEST_WINDOW (header_window),
2274 gtk_widget_destroy (GTK_WIDGET (header_window));
2276 gtk_widget_show_all (GTK_WIDGET (header_window));
2278 g_object_unref (folder);
2284 /* Restore window title */
2285 update_window_title (self);
2286 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2287 g_object_unref (self);
2292 /* Get the window */
2293 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2294 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2295 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2297 /* Update the row reference */
2298 if (priv->row_reference != NULL) {
2299 gtk_tree_row_reference_free (priv->row_reference);
2300 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2301 if (priv->next_row_reference != NULL) {
2302 gtk_tree_row_reference_free (priv->next_row_reference);
2304 if (priv->row_reference) {
2305 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2306 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2308 priv->next_row_reference = NULL;
2312 /* Mark header as read */
2313 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2314 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2316 /* Set new message */
2317 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2318 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2319 modest_msg_view_window_update_priority (self);
2320 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2321 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2322 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2325 /* Set the new message uid of the window */
2326 if (priv->msg_uid) {
2327 g_free (priv->msg_uid);
2328 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2331 /* Notify the observers */
2332 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2333 0, priv->header_model, priv->row_reference);
2335 /* Sync the flags if the message is not opened from a header
2336 model, i.e, if it's opened from a notification */
2337 if (!priv->header_model)
2341 g_object_unref (self);
2343 gtk_tree_row_reference_free (row_reference);
2347 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2349 ModestMsgViewWindowPrivate *priv;
2351 TnyFolderType folder_type;
2353 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2355 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2357 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2361 folder = tny_msg_get_folder (msg);
2363 folder_type = modest_tny_folder_guess_folder_type (folder);
2364 g_object_unref (folder);
2366 g_object_unref (msg);
2374 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2376 ModestMsgViewWindowPrivate *priv;
2377 TnyHeader *header = NULL;
2378 TnyHeaderFlags flags = 0;
2380 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2382 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2384 GtkTreePath *path = NULL;
2386 path = gtk_tree_row_reference_get_path (priv->row_reference);
2387 g_return_if_fail (path != NULL);
2388 gtk_tree_model_get_iter (priv->header_model,
2390 gtk_tree_row_reference_get_path (priv->row_reference));
2392 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2394 gtk_tree_path_free (path);
2397 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2399 header = tny_msg_get_header (msg);
2400 g_object_unref (msg);
2405 flags = tny_header_get_flags (header);
2406 g_object_unref(G_OBJECT(header));
2409 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2414 toolbar_resize (ModestMsgViewWindow *self)
2416 ModestMsgViewWindowPrivate *priv = NULL;
2417 ModestWindowPrivate *parent_priv = NULL;
2419 gint static_button_size;
2420 ModestWindowMgr *mgr;
2422 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2423 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2424 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2426 mgr = modest_runtime_get_window_mgr ();
2427 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2429 if (parent_priv->toolbar) {
2430 /* Set expandable and homogeneous tool buttons */
2431 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2432 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2433 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2434 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2435 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2436 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2437 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2438 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2439 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2440 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2441 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2442 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2443 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2444 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2445 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2446 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2447 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2448 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2449 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2454 modest_msg_view_window_show_toolbar (ModestWindow *self,
2455 gboolean show_toolbar)
2457 ModestMsgViewWindowPrivate *priv = NULL;
2458 ModestWindowPrivate *parent_priv;
2460 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2461 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2463 /* Set optimized view status */
2464 priv->optimized_view = !show_toolbar;
2466 if (!parent_priv->toolbar) {
2467 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2469 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2470 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2472 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2473 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2474 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2477 hildon_window_add_toolbar (HILDON_WINDOW (self),
2478 GTK_TOOLBAR (parent_priv->toolbar));
2483 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2484 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2485 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2487 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2488 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2489 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2491 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2494 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2495 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2500 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2502 ModestMsgViewWindow *window)
2504 if (!GTK_WIDGET_VISIBLE (window))
2507 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2511 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2513 ModestMsgViewWindowPrivate *priv;
2515 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2516 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2518 return priv->progress_hint;
2522 observers_empty (ModestMsgViewWindow *self)
2525 ModestMsgViewWindowPrivate *priv;
2526 gboolean is_empty = TRUE;
2527 guint pending_ops = 0;
2529 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2530 tmp = priv->progress_widgets;
2532 /* Check all observers */
2533 while (tmp && is_empty) {
2534 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2535 is_empty = pending_ops == 0;
2537 tmp = g_slist_next(tmp);
2544 on_account_removed (TnyAccountStore *account_store,
2545 TnyAccount *account,
2548 /* Do nothing if it's a transport account, because we only
2549 show the messages of a store account */
2550 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2551 const gchar *parent_acc = NULL;
2552 const gchar *our_acc = NULL;
2554 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2555 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2557 /* Close this window if I'm showing a message of the removed account */
2558 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2559 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2564 on_mail_operation_started (ModestMailOperation *mail_op,
2567 ModestMsgViewWindow *self;
2568 ModestMailOperationTypeOperation op_type;
2570 ModestMsgViewWindowPrivate *priv;
2571 GObject *source = NULL;
2573 self = MODEST_MSG_VIEW_WINDOW (user_data);
2574 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2575 op_type = modest_mail_operation_get_type_operation (mail_op);
2576 tmp = priv->progress_widgets;
2577 source = modest_mail_operation_get_source(mail_op);
2578 if (G_OBJECT (self) == source) {
2579 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2580 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2581 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2582 set_progress_hint (self, TRUE);
2584 modest_progress_object_add_operation (
2585 MODEST_PROGRESS_OBJECT (tmp->data),
2587 tmp = g_slist_next (tmp);
2591 g_object_unref (source);
2593 /* Update dimming rules */
2594 check_dimming_rules_after_change (self);
2598 on_mail_operation_finished (ModestMailOperation *mail_op,
2601 ModestMsgViewWindow *self;
2602 ModestMailOperationTypeOperation op_type;
2604 ModestMsgViewWindowPrivate *priv;
2606 self = MODEST_MSG_VIEW_WINDOW (user_data);
2607 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2608 op_type = modest_mail_operation_get_type_operation (mail_op);
2609 tmp = priv->progress_widgets;
2611 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2612 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2613 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2615 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2617 tmp = g_slist_next (tmp);
2620 /* If no more operations are being observed, NORMAL mode is enabled again */
2621 if (observers_empty (self)) {
2622 set_progress_hint (self, FALSE);
2626 /* Update dimming rules. We have to do this right here
2627 and not in view_msg_cb because at that point the
2628 transfer mode is still enabled so the dimming rule
2629 won't let the user delete the message that has been
2630 readed for example */
2631 check_dimming_rules_after_change (self);
2635 on_queue_changed (ModestMailOperationQueue *queue,
2636 ModestMailOperation *mail_op,
2637 ModestMailOperationQueueNotification type,
2638 ModestMsgViewWindow *self)
2640 ModestMsgViewWindowPrivate *priv;
2642 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2644 /* If this operations was created by another window, do nothing */
2645 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2648 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2649 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2651 "operation-started",
2652 G_CALLBACK (on_mail_operation_started),
2654 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2656 "operation-finished",
2657 G_CALLBACK (on_mail_operation_finished),
2659 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2660 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2662 "operation-started");
2663 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2665 "operation-finished");
2670 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2672 ModestMsgViewWindowPrivate *priv;
2673 TnyList *selected_attachments = NULL;
2675 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2676 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2678 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2679 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2681 return selected_attachments;
2685 ModestMsgViewWindow *self;
2687 gchar *attachment_uid;
2688 } DecodeAsyncHelper;
2691 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2697 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2698 const gchar *content_type;
2699 ModestMsgViewWindowPrivate *priv;
2701 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2703 if (cancelled || err) {
2706 if ((err->domain == TNY_ERROR_DOMAIN) &&
2707 (err->code == TNY_IO_ERROR_WRITE) &&
2708 (errno == ENOSPC)) {
2709 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2711 msg = g_strdup (_("mail_ib_file_operation_failed"));
2713 modest_platform_information_banner (NULL, NULL, msg);
2719 /* It could happen that the window was closed. So we
2720 assume it is a cancelation */
2721 if (!GTK_WIDGET_VISIBLE (helper->self))
2724 /* Remove the progress hint */
2725 set_progress_hint (helper->self, FALSE);
2727 content_type = tny_mime_part_get_content_type (mime_part);
2728 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2729 ModestWindowMgr *mgr;
2730 ModestWindow *msg_win = NULL;
2733 const gchar *mailbox;
2734 TnyStream *file_stream;
2737 fd = g_open (helper->file_path, O_RDONLY, 0644);
2740 file_stream = tny_fs_stream_new (fd);
2742 mgr = modest_runtime_get_window_mgr ();
2744 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2745 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2748 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2750 msg = tny_camel_msg_new ();
2751 tny_camel_msg_parse (msg, file_stream);
2754 top_msg = g_object_ref (priv->top_msg);
2756 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2758 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2759 account, mailbox, helper->attachment_uid);
2760 if (top_msg) g_object_unref (top_msg);
2761 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2762 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2763 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2764 gtk_widget_show_all (GTK_WIDGET (msg_win));
2766 gtk_widget_destroy (GTK_WIDGET (msg_win));
2767 g_object_unref (msg);
2768 g_object_unref (file_stream);
2770 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2775 /* make the file read-only */
2776 g_chmod(helper->file_path, 0444);
2778 /* Activate the file */
2779 modest_platform_activate_file (helper->file_path, content_type);
2784 g_object_unref (helper->self);
2785 g_free (helper->file_path);
2786 g_free (helper->attachment_uid);
2787 g_slice_free (DecodeAsyncHelper, helper);
2791 view_attachment_connect_handler (gboolean canceled,
2793 GtkWindow *parent_window,
2794 TnyAccount *account,
2798 if (canceled || err) {
2799 g_object_unref (part);
2803 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2805 g_object_unref (part);
2809 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2810 TnyMimePart *mime_part)
2812 ModestMsgViewWindowPrivate *priv;
2813 const gchar *msg_uid;
2814 gchar *attachment_uid = NULL;
2815 gint attachment_index = 0;
2816 TnyList *attachments;
2818 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2819 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2820 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2822 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2823 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2824 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2825 g_object_unref (attachments);
2827 if (msg_uid && attachment_index >= 0) {
2828 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2831 if (mime_part == NULL) {
2832 gboolean error = FALSE;
2833 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2834 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2836 } else if (tny_list_get_length (selected_attachments) > 1) {
2837 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2841 iter = tny_list_create_iterator (selected_attachments);
2842 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2843 g_object_unref (iter);
2845 if (selected_attachments)
2846 g_object_unref (selected_attachments);
2851 g_object_ref (mime_part);
2854 if (tny_mime_part_is_purged (mime_part))
2857 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2858 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2860 TnyAccount *account;
2862 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2864 /* Get the account */
2866 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2869 if (!tny_device_is_online (modest_runtime_get_device())) {
2870 modest_platform_connect_and_perform (GTK_WINDOW (window),
2872 TNY_ACCOUNT (account),
2873 (ModestConnectedPerformer) view_attachment_connect_handler,
2874 g_object_ref (mime_part));
2879 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2880 gchar *filepath = NULL;
2881 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2882 gboolean show_error_banner = FALSE;
2883 TnyFsStream *temp_stream = NULL;
2884 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2887 if (temp_stream != NULL) {
2888 ModestAccountMgr *mgr;
2889 DecodeAsyncHelper *helper;
2890 gboolean decode_in_provider;
2891 ModestProtocol *protocol;
2892 const gchar *account;
2894 /* Activate progress hint */
2895 set_progress_hint (window, TRUE);
2897 helper = g_slice_new0 (DecodeAsyncHelper);
2898 helper->self = g_object_ref (window);
2899 helper->file_path = g_strdup (filepath);
2900 helper->attachment_uid = g_strdup (attachment_uid);
2902 decode_in_provider = FALSE;
2903 mgr = modest_runtime_get_account_mgr ();
2904 account = modest_window_get_active_account (MODEST_WINDOW (window));
2905 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2906 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2908 uri = g_strconcat ("file://", filepath, NULL);
2909 decode_in_provider =
2910 modest_account_protocol_decode_part_to_stream_async (
2911 MODEST_ACCOUNT_PROTOCOL (protocol),
2914 TNY_STREAM (temp_stream),
2915 on_decode_to_stream_async_handler,
2922 if (!decode_in_provider)
2923 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2924 on_decode_to_stream_async_handler,
2927 g_object_unref (temp_stream);
2928 /* NOTE: files in the temporary area will be automatically
2929 * cleaned after some time if they are no longer in use */
2932 const gchar *content_type;
2933 /* the file may already exist but it isn't writable,
2934 * let's try to open it anyway */
2935 content_type = tny_mime_part_get_content_type (mime_part);
2936 modest_platform_activate_file (filepath, content_type);
2938 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2939 show_error_banner = TRUE;
2944 if (show_error_banner)
2945 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2946 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2947 ModestWindowMgr *mgr;
2948 ModestWindow *msg_win = NULL;
2949 TnyMsg *current_msg;
2953 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2954 mgr = modest_runtime_get_window_mgr ();
2955 header = tny_msg_get_header (TNY_MSG (current_msg));
2956 found = modest_window_mgr_find_registered_message_uid (mgr,
2961 g_debug ("window for this body is already being created");
2965 /* it's not found, so create a new window for it */
2966 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2967 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2968 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2970 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2973 top_msg = g_object_ref (priv->top_msg);
2975 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2977 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
2978 account, mailbox, attachment_uid);
2980 if (top_msg) g_object_unref (top_msg);
2982 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2983 modest_window_get_zoom (MODEST_WINDOW (window)));
2984 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2985 gtk_widget_show_all (GTK_WIDGET (msg_win));
2987 gtk_widget_destroy (GTK_WIDGET (msg_win));
2989 g_object_unref (current_msg);
2991 /* message attachment */
2992 TnyHeader *header = NULL;
2993 ModestWindowMgr *mgr;
2994 ModestWindow *msg_win = NULL;
2997 header = tny_msg_get_header (TNY_MSG (mime_part));
2998 mgr = modest_runtime_get_window_mgr ();
2999 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3002 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3003 * thus, we don't do anything */
3004 g_debug ("window for is already being created");
3007 /* it's not found, so create a new window for it */
3008 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3009 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3010 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3012 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3014 top_msg = g_object_ref (priv->top_msg);
3016 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3017 msg_win = modest_msg_view_window_new_for_attachment (
3018 TNY_MSG (mime_part), top_msg, account,
3019 mailbox, attachment_uid);
3020 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3021 modest_window_get_zoom (MODEST_WINDOW (window)));
3022 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3023 gtk_widget_show_all (GTK_WIDGET (msg_win));
3025 gtk_widget_destroy (GTK_WIDGET (msg_win));
3031 g_free (attachment_uid);
3033 g_object_unref (mime_part);
3045 GnomeVFSResult result;
3047 ModestMsgViewWindow *window;
3050 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3051 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3052 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3053 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3056 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3060 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3061 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3062 g_free (pair->filename);
3063 g_object_unref (pair->part);
3064 g_slice_free (SaveMimePartPair, pair);
3066 g_list_free (info->pairs);
3069 g_object_unref (info->window);
3070 info->window = NULL;
3072 g_slice_free (SaveMimePartInfo, info);
3077 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3079 /* This is a GDK lock because we are an idle callback and
3080 * hildon_banner_show_information is or does Gtk+ code */
3082 gdk_threads_enter (); /* CHECKED */
3083 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3085 } else if (info->result == GNOME_VFS_OK) {
3086 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
3087 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3090 /* Check if the uri belongs to the external mmc */
3091 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3092 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3094 msg = g_strdup (_KR("cerm_memory_card_full"));
3095 modest_platform_information_banner (NULL, NULL, msg);
3098 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
3100 save_mime_part_info_free (info, FALSE);
3101 gdk_threads_leave (); /* CHECKED */
3107 save_mime_part_to_file_connect_handler (gboolean canceled,
3109 GtkWindow *parent_window,
3110 TnyAccount *account,
3111 SaveMimePartInfo *info)
3113 if (canceled || err) {
3114 if (canceled && !err) {
3115 info->result = GNOME_VFS_ERROR_CANCELLED;
3117 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3119 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3124 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3127 TnyAccount *account;
3128 ModestMsgViewWindowPrivate *priv;
3130 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3132 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3135 /* Get the account */
3137 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3140 modest_platform_connect_and_perform (GTK_WINDOW (info->window),
3142 TNY_ACCOUNT (account),
3143 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3147 g_object_unref (account);
3153 save_mime_part_to_file (SaveMimePartInfo *info)
3155 GnomeVFSHandle *handle;
3157 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3159 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3160 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3161 gboolean check_online = TRUE;
3162 ModestMsgViewWindowPrivate *priv = NULL;
3164 /* Check if we really need to connect to save the mime part */
3165 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3166 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3167 check_online = FALSE;
3169 TnyAccountStore *acc_store;
3170 TnyAccount *account = NULL;
3172 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3173 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3176 if (tny_account_get_connection_status (account) ==
3177 TNY_CONNECTION_STATUS_CONNECTED)
3178 check_online = FALSE;
3179 g_object_unref (account);
3181 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3186 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3191 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3192 if (info->result == GNOME_VFS_OK) {
3193 GError *error = NULL;
3194 gboolean decode_in_provider;
3196 ModestAccountMgr *mgr;
3197 const gchar *account;
3198 ModestProtocol *protocol = NULL;
3200 stream = tny_vfs_stream_new (handle);
3202 decode_in_provider = FALSE;
3203 mgr = modest_runtime_get_account_mgr ();
3204 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3205 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3206 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3207 decode_in_provider =
3208 modest_account_protocol_decode_part_to_stream (
3209 MODEST_ACCOUNT_PROTOCOL (protocol),
3217 if (!decode_in_provider)
3218 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3221 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3223 if ((error->domain == TNY_ERROR_DOMAIN) &&
3224 (error->code == TNY_IO_ERROR_WRITE) &&
3225 (errno == ENOSPC)) {
3226 info->result = GNOME_VFS_ERROR_NO_SPACE;
3228 info->result = GNOME_VFS_ERROR_IO;
3231 g_object_unref (G_OBJECT (stream));
3233 g_warning ("Could not create save attachment %s: %s\n",
3234 pair->filename, gnome_vfs_result_to_string (info->result));
3237 /* Go on saving remaining files */
3238 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3239 if (info->pairs != NULL) {
3240 save_mime_part_to_file (info);
3242 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3249 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3250 SaveMimePartInfo *info)
3252 gboolean is_ok = TRUE;
3253 gint replaced_files = 0;
3254 const GList *files = info->pairs;
3255 const GList *iter, *to_replace = NULL;
3257 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3258 SaveMimePartPair *pair = iter->data;
3259 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3261 if (modest_utils_file_exists (unescaped)) {
3263 if (replaced_files == 1)
3268 if (replaced_files) {
3271 if (replaced_files == 1) {
3272 SaveMimePartPair *pair = to_replace->data;
3273 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3274 gchar *escaped_basename, *message;
3276 escaped_basename = g_uri_unescape_string (basename, NULL);
3277 message = g_strdup_printf ("%s\n%s",
3278 _FM("docm_nc_replace_file"),
3279 (escaped_basename) ? escaped_basename : "");
3280 response = modest_platform_run_confirmation_dialog (parent, message);
3282 g_free (escaped_basename);
3284 response = modest_platform_run_confirmation_dialog (parent,
3285 _FM("docm_nc_replace_multiple"));
3287 if (response != GTK_RESPONSE_OK)
3292 save_mime_part_info_free (info, TRUE);
3294 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3299 typedef struct _SaveAttachmentsInfo {
3300 TnyList *attachments_list;
3301 ModestMsgViewWindow *window;
3302 } SaveAttachmentsInfo;
3305 save_attachments_response (GtkDialog *dialog,
3309 TnyList *mime_parts;
3311 GList *files_to_save = NULL;
3312 gchar *current_folder;
3313 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3315 mime_parts = TNY_LIST (sa_info->attachments_list);
3317 if (arg1 != GTK_RESPONSE_OK)
3320 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3321 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3322 if (current_folder && *current_folder != '\0') {
3324 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3325 current_folder,&err);
3327 g_debug ("Error storing latest used folder: %s", err->message);
3331 g_free (current_folder);
3333 if (!modest_utils_folder_writable (chooser_uri)) {
3334 const gchar *err_msg;
3336 #ifdef MODEST_PLATFORM_MAEMO
3337 if (modest_maemo_utils_in_usb_mode ()) {
3338 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3340 err_msg = _FM("sfil_ib_readonly_location");
3343 err_msg = _FM("sfil_ib_readonly_location");
3345 hildon_banner_show_information (NULL, NULL, err_msg);
3349 iter = tny_list_create_iterator (mime_parts);
3350 while (!tny_iterator_is_done (iter)) {
3351 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3353 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3354 !tny_mime_part_is_purged (mime_part) &&
3355 (tny_mime_part_get_filename (mime_part) != NULL)) {
3356 SaveMimePartPair *pair;
3358 pair = g_slice_new0 (SaveMimePartPair);
3360 if (tny_list_get_length (mime_parts) > 1) {
3362 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3363 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3366 pair->filename = g_strdup (chooser_uri);
3368 pair->part = mime_part;
3369 files_to_save = g_list_prepend (files_to_save, pair);
3371 tny_iterator_next (iter);
3373 g_object_unref (iter);
3376 if (files_to_save != NULL) {
3377 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3378 info->pairs = files_to_save;
3379 info->result = TRUE;
3380 info->uri = g_strdup (chooser_uri);
3381 info->window = g_object_ref (sa_info->window);
3382 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3384 g_free (chooser_uri);
3387 /* Free and close the dialog */
3388 g_object_unref (mime_parts);
3389 g_object_unref (sa_info->window);
3390 g_slice_free (SaveAttachmentsInfo, sa_info);
3391 gtk_widget_destroy (GTK_WIDGET (dialog));
3395 msg_is_attachment (TnyList *mime_parts)
3398 gboolean retval = FALSE;
3400 if (tny_list_get_length (mime_parts) > 1)
3403 iter = tny_list_create_iterator (mime_parts);
3405 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3407 if (TNY_IS_MSG (part))
3409 g_object_unref (part);
3411 g_object_unref (iter);
3417 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3418 TnyList *mime_parts)
3420 ModestMsgViewWindowPrivate *priv;
3421 GtkWidget *save_dialog = NULL;
3422 gchar *conf_folder = NULL;
3423 gchar *filename = NULL;
3424 gchar *save_multiple_str = NULL;
3425 const gchar *root_folder = "file:///";
3427 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3428 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3430 if (mime_parts == NULL) {
3431 gboolean allow_msgs = FALSE;
3433 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3434 * selection available */
3435 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3437 /* Check if the message is composed by an unique MIME
3438 part whose content disposition is attachment. There
3439 could be messages like this:
3441 Date: Tue, 12 Jan 2010 20:40:59 +0000
3442 From: <sender@example.org>
3443 To: <recipient@example.org>
3445 Content-Type: image/jpeg
3446 Content-Disposition: attachment; filename="bug7718.jpeg"
3448 whose unique MIME part is the message itself whose
3449 content disposition is attachment
3451 if (mime_parts && msg_is_attachment (mime_parts))
3455 !modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, allow_msgs)) {
3456 g_object_unref (mime_parts);
3459 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3461 g_object_unref (mime_parts);
3467 g_object_ref (mime_parts);
3470 /* prepare dialog */
3471 if (tny_list_get_length (mime_parts) == 1) {
3473 /* only one attachment selected */
3474 iter = tny_list_create_iterator (mime_parts);
3475 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3476 g_object_unref (iter);
3477 if (!modest_tny_mime_part_is_msg (mime_part) &&
3478 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3479 !tny_mime_part_is_purged (mime_part)) {
3480 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3482 /* TODO: show any error? */
3483 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3484 g_object_unref (mime_parts);
3487 g_object_unref (mime_part);
3489 gint num = tny_list_get_length (mime_parts);
3490 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3491 "sfil_va_number_of_objects_attachment",
3492 "sfil_va_number_of_objects_attachments",
3496 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
3497 GTK_FILE_CHOOSER_ACTION_SAVE);
3499 /* Get last used folder */
3500 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3501 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3503 /* File chooser stops working if we select "file:///" as current folder */
3504 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3505 g_free (conf_folder);
3509 if (conf_folder && conf_folder[0] != '\0') {
3510 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3513 /* Set the default folder to documents folder */
3514 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3517 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3519 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3520 g_free (docs_folder);
3522 g_free (conf_folder);
3526 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3531 /* if multiple, set multiple string */
3532 if (save_multiple_str) {
3533 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3534 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
3535 g_free (save_multiple_str);
3538 /* We must run this asynchronously, because the hildon dialog
3539 performs a gtk_dialog_run by itself which leads to gdk
3541 SaveAttachmentsInfo *sa_info;
3542 sa_info = g_slice_new (SaveAttachmentsInfo);
3543 sa_info->attachments_list = mime_parts;
3544 sa_info->window = g_object_ref (window);
3545 g_signal_connect (save_dialog, "response",
3546 G_CALLBACK (save_attachments_response), sa_info);
3548 gtk_widget_show_all (save_dialog);
3552 show_remove_attachment_information (gpointer userdata)
3554 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3555 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3557 /* We're outside the main lock */
3558 gdk_threads_enter ();
3560 if (priv->remove_attachment_banner != NULL) {
3561 gtk_widget_destroy (priv->remove_attachment_banner);
3562 g_object_unref (priv->remove_attachment_banner);
3565 priv->remove_attachment_banner = g_object_ref (
3566 hildon_banner_show_animation (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3568 gdk_threads_leave ();
3574 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3576 ModestMsgViewWindowPrivate *priv;
3577 TnyList *mime_parts = NULL, *tmp;
3578 gchar *confirmation_message;
3584 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3585 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3587 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3588 * because we don't have selection
3590 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3592 /* Remove already purged messages from mime parts list. We use
3593 a copy of the list to remove items in the original one */
3594 tmp = tny_list_copy (mime_parts);
3595 iter = tny_list_create_iterator (tmp);
3596 while (!tny_iterator_is_done (iter)) {
3597 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3598 if (tny_mime_part_is_purged (part))
3599 tny_list_remove (mime_parts, (GObject *) part);
3601 g_object_unref (part);
3602 tny_iterator_next (iter);
3604 g_object_unref (tmp);
3605 g_object_unref (iter);
3607 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3608 tny_list_get_length (mime_parts) == 0) {
3609 g_object_unref (mime_parts);
3613 n_attachments = tny_list_get_length (mime_parts);
3614 if (n_attachments == 1) {
3618 iter = tny_list_create_iterator (mime_parts);
3619 part = (TnyMimePart *) tny_iterator_get_current (iter);
3620 g_object_unref (iter);
3621 if (modest_tny_mime_part_is_msg (part)) {
3623 header = tny_msg_get_header (TNY_MSG (part));
3624 filename = tny_header_dup_subject (header);
3625 g_object_unref (header);
3626 if (filename == NULL)
3627 filename = g_strdup (_("mail_va_no_subject"));
3629 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3631 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3633 g_object_unref (part);
3635 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3636 "mcen_nc_purge_files_text",
3637 n_attachments), n_attachments);
3639 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3640 confirmation_message);
3641 g_free (confirmation_message);
3643 if (response != GTK_RESPONSE_OK) {
3644 g_object_unref (mime_parts);
3648 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3650 iter = tny_list_create_iterator (mime_parts);
3651 while (!tny_iterator_is_done (iter)) {
3654 part = (TnyMimePart *) tny_iterator_get_current (iter);
3655 tny_mime_part_set_purged (TNY_MIME_PART (part));
3656 g_object_unref (part);
3657 tny_iterator_next (iter);
3659 g_object_unref (iter);
3661 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3662 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3663 tny_msg_rewrite_cache (msg);
3664 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3665 g_object_unref (msg);
3666 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3668 g_object_unref (mime_parts);
3670 if (priv->purge_timeout > 0) {
3671 g_source_remove (priv->purge_timeout);
3672 priv->purge_timeout = 0;
3675 if (priv->remove_attachment_banner) {
3676 gtk_widget_destroy (priv->remove_attachment_banner);
3677 g_object_unref (priv->remove_attachment_banner);
3678 priv->remove_attachment_banner = NULL;
3684 update_window_title (ModestMsgViewWindow *window)
3686 ModestMsgViewWindowPrivate *priv;
3688 TnyHeader *header = NULL;
3689 gchar *subject = NULL;
3691 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3693 /* Note that if the window is closed while we're retrieving
3694 the message, this widget could de deleted */
3695 if (!priv->msg_view)
3698 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3700 if (priv->other_body) {
3703 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3705 g_strstrip (description);
3706 subject = description;
3708 } else if (msg != NULL) {
3709 header = tny_msg_get_header (msg);
3710 subject = tny_header_dup_subject (header);
3711 g_object_unref (header);
3712 g_object_unref (msg);
3715 if ((subject == NULL)||(subject[0] == '\0')) {
3717 subject = g_strdup (_("mail_va_no_subject"));
3720 gtk_window_set_title (GTK_WINDOW (window), subject);
3725 on_move_focus (GtkWidget *widget,
3726 GtkDirectionType direction,
3729 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3733 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3735 GnomeVFSResult result;
3736 GnomeVFSHandle *handle = NULL;
3737 GnomeVFSFileInfo *info = NULL;
3740 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3741 if (result != GNOME_VFS_OK) {
3746 info = gnome_vfs_file_info_new ();
3747 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3748 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3749 /* We put a "safe" default size for going to cache */
3750 *expected_size = (300*1024);
3752 *expected_size = info->size;
3754 gnome_vfs_file_info_unref (info);
3756 stream = tny_vfs_stream_new (handle);
3765 TnyStream *output_stream;
3766 GtkWidget *msg_view;
3771 on_fetch_image_timeout_refresh_view (gpointer userdata)
3773 ModestMsgViewWindowPrivate *priv;
3775 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3776 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3777 /* Note that priv->msg_view is set to NULL when this window is
3779 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3780 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3782 priv->fetch_image_redraw_handler = 0;
3783 g_object_unref (userdata);
3788 on_fetch_image_idle_refresh_view (gpointer userdata)
3791 FetchImageData *fidata = (FetchImageData *) userdata;
3793 gdk_threads_enter ();
3794 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3795 ModestMsgViewWindowPrivate *priv;
3797 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3798 priv->fetching_images--;
3799 if (priv->fetch_image_redraw_handler == 0) {
3800 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3804 gdk_threads_leave ();
3806 g_object_unref (fidata->msg_view);
3807 g_object_unref (fidata->window);
3808 g_slice_free (FetchImageData, fidata);
3813 on_fetch_image_thread (gpointer userdata)
3815 FetchImageData *fidata = (FetchImageData *) userdata;
3816 TnyStreamCache *cache;
3817 TnyStream *cache_stream;
3819 cache = modest_runtime_get_images_cache ();
3821 tny_stream_cache_get_stream (cache,
3823 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3824 (gpointer) fidata->uri);
3825 g_free (fidata->cache_id);
3826 g_free (fidata->uri);
3828 if (cache_stream != NULL) {
3831 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3834 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3835 if (G_UNLIKELY (nb_read < 0)) {
3837 } else if (G_LIKELY (nb_read > 0)) {
3838 gssize nb_written = 0;
3840 while (G_UNLIKELY (nb_written < nb_read)) {
3843 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3844 nb_read - nb_written);
3845 if (G_UNLIKELY (len < 0))
3851 tny_stream_close (cache_stream);
3852 g_object_unref (cache_stream);
3855 tny_stream_close (fidata->output_stream);
3856 g_object_unref (fidata->output_stream);
3858 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3864 on_fetch_image (ModestMsgView *msgview,
3867 ModestMsgViewWindow *window)
3869 const gchar *current_account;
3870 ModestMsgViewWindowPrivate *priv;
3871 FetchImageData *fidata;
3873 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3875 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3877 fidata = g_slice_new0 (FetchImageData);
3878 fidata->msg_view = g_object_ref (msgview);
3879 fidata->window = g_object_ref (window);
3880 fidata->uri = g_strdup (uri);
3881 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3882 fidata->output_stream = g_object_ref (stream);
3884 priv->fetching_images++;
3885 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3886 g_object_unref (fidata->output_stream);
3887 g_free (fidata->cache_id);
3888 g_free (fidata->uri);
3889 g_object_unref (fidata->msg_view);
3890 g_slice_free (FetchImageData, fidata);
3891 tny_stream_close (stream);
3892 priv->fetching_images--;
3893 update_progress_hint (window);
3896 update_progress_hint (window);
3902 setup_menu (ModestMsgViewWindow *self)
3904 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3906 /* Settings menu buttons */
3907 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3908 APP_MENU_CALLBACK (modest_msg_view_window_show_find_toolbar),
3909 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3911 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self),
3912 dngettext(GETTEXT_PACKAGE,
3913 "mcen_me_move_message",
3914 "mcen_me_move_messages",
3917 APP_MENU_CALLBACK (modest_ui_actions_on_move_to),
3918 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3920 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3921 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3922 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3924 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3925 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3926 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3928 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3929 APP_MENU_CALLBACK (modest_ui_actions_save_attachments),
3930 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3931 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3932 APP_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3933 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3935 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3936 APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3937 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3938 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3939 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3940 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3942 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3943 APP_MENU_CALLBACK (modest_ui_actions_on_details),
3944 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3948 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3950 ModestMsgViewWindowPrivate *priv;
3951 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3952 GSList *recipients = NULL;
3955 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3959 header = modest_msg_view_window_get_header (self);
3962 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3963 g_object_unref (header);
3965 recipients = modest_tny_msg_get_all_recipients_list (msg);
3966 g_object_unref (msg);
3970 /* Offer the user to add recipients to the address book */
3971 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3972 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3977 _modest_msg_view_window_map_event (GtkWidget *widget,
3981 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
3983 update_progress_hint (self);
3989 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
3991 ModestMsgViewWindowPrivate *priv;
3992 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3994 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
3998 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4000 ModestMsgViewWindowPrivate *priv;
4001 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4003 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4005 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4009 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4011 ModestMsgViewWindowPrivate *priv;
4012 const gchar *msg_uid;
4013 TnyHeader *header = NULL;
4014 TnyFolder *folder = NULL;
4016 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4018 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4020 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4024 folder = tny_header_get_folder (header);
4025 g_object_unref (header);
4030 msg_uid = modest_msg_view_window_get_message_uid (self);
4032 GtkTreeRowReference *row_reference;
4034 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4035 row_reference = priv->row_reference;
4037 row_reference = NULL;
4039 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4040 g_warning ("Shouldn't happen, trying to reload a message failed");
4043 g_object_unref (folder);
4047 update_branding (ModestMsgViewWindow *self)
4049 const gchar *account;
4050 const gchar *mailbox;
4051 ModestAccountMgr *mgr;
4052 ModestProtocol *protocol = NULL;
4053 gchar *service_name = NULL;
4054 const GdkPixbuf *service_icon = NULL;
4055 ModestMsgViewWindowPrivate *priv;
4057 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4059 account = modest_window_get_active_account (MODEST_WINDOW (self));
4060 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4062 mgr = modest_runtime_get_account_mgr ();
4064 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4065 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4066 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4068 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4069 account, mailbox, MODEST_ICON_SIZE_SMALL);
4073 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4074 g_free (service_name);
4078 sync_flags (ModestMsgViewWindow *self)
4080 TnyHeader *header = NULL;
4082 header = modest_msg_view_window_get_header (self);
4084 TnyMsg *msg = modest_msg_view_window_get_message (self);
4086 header = tny_msg_get_header (msg);
4087 g_object_unref (msg);
4092 TnyFolder *folder = tny_header_get_folder (header);
4095 ModestMailOperation *mail_op;
4097 /* Sync folder, we need this to save the seen flag */
4098 mail_op = modest_mail_operation_new (NULL);
4099 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4101 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4102 g_object_unref (mail_op);
4103 g_object_unref (folder);
4105 g_object_unref (header);
4110 on_realize (GtkWidget *widget,
4113 GdkDisplay *display;
4115 unsigned long val = 1;
4117 display = gdk_drawable_get_display (widget->window);
4118 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4119 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4120 GDK_WINDOW_XID (widget->window), atom,
4121 XA_INTEGER, 32, PropModeReplace,
4122 (unsigned char *) &val, 1);
4128 on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
4130 const gchar *account_name;
4131 ModestProtocolType proto_type;
4132 ModestProtocol *protocol;
4133 gboolean retval = FALSE;
4135 account_name = modest_window_get_active_account (MODEST_WINDOW (self));
4138 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
4141 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
4144 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4145 retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
4146 calendar_part, container);