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)) {
2316 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2317 uid = modest_tny_folder_get_header_unique_id (header);
2318 modest_platform_emit_msg_read_changed_signal (uid, TRUE);
2322 /* Set new message */
2323 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2324 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2325 modest_msg_view_window_update_priority (self);
2326 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2327 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2328 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2331 /* Set the new message uid of the window */
2332 if (priv->msg_uid) {
2333 g_free (priv->msg_uid);
2334 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2337 /* Notify the observers */
2338 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2339 0, priv->header_model, priv->row_reference);
2341 /* Sync the flags if the message is not opened from a header
2342 model, i.e, if it's opened from a notification */
2343 if (!priv->header_model)
2347 g_object_unref (self);
2349 gtk_tree_row_reference_free (row_reference);
2353 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2355 ModestMsgViewWindowPrivate *priv;
2357 TnyFolderType folder_type;
2359 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2361 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2363 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2367 folder = tny_msg_get_folder (msg);
2369 folder_type = modest_tny_folder_guess_folder_type (folder);
2370 g_object_unref (folder);
2372 g_object_unref (msg);
2380 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2382 ModestMsgViewWindowPrivate *priv;
2383 TnyHeader *header = NULL;
2384 TnyHeaderFlags flags = 0;
2386 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2388 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2390 GtkTreePath *path = NULL;
2392 path = gtk_tree_row_reference_get_path (priv->row_reference);
2393 g_return_if_fail (path != NULL);
2394 gtk_tree_model_get_iter (priv->header_model,
2396 gtk_tree_row_reference_get_path (priv->row_reference));
2398 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2400 gtk_tree_path_free (path);
2403 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2405 header = tny_msg_get_header (msg);
2406 g_object_unref (msg);
2411 flags = tny_header_get_flags (header);
2412 g_object_unref(G_OBJECT(header));
2415 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2420 toolbar_resize (ModestMsgViewWindow *self)
2422 ModestMsgViewWindowPrivate *priv = NULL;
2423 ModestWindowPrivate *parent_priv = NULL;
2425 gint static_button_size;
2426 ModestWindowMgr *mgr;
2428 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2429 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2430 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2432 mgr = modest_runtime_get_window_mgr ();
2433 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2435 if (parent_priv->toolbar) {
2436 /* Set expandable and homogeneous tool buttons */
2437 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
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/ToolbarMessageReplyAll");
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/ToolbarMessageForward");
2444 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2445 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2446 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2447 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2448 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2449 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2450 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2451 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2452 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2453 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2454 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2455 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2460 modest_msg_view_window_show_toolbar (ModestWindow *self,
2461 gboolean show_toolbar)
2463 ModestMsgViewWindowPrivate *priv = NULL;
2464 ModestWindowPrivate *parent_priv;
2466 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2467 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2469 /* Set optimized view status */
2470 priv->optimized_view = !show_toolbar;
2472 if (!parent_priv->toolbar) {
2473 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2475 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2476 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2478 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2479 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2480 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2483 hildon_window_add_toolbar (HILDON_WINDOW (self),
2484 GTK_TOOLBAR (parent_priv->toolbar));
2489 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2490 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2491 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2493 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2494 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2495 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2497 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2500 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2501 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2506 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2508 ModestMsgViewWindow *window)
2510 if (!GTK_WIDGET_VISIBLE (window))
2513 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2517 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2519 ModestMsgViewWindowPrivate *priv;
2521 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2522 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2524 return priv->progress_hint;
2528 observers_empty (ModestMsgViewWindow *self)
2531 ModestMsgViewWindowPrivate *priv;
2532 gboolean is_empty = TRUE;
2533 guint pending_ops = 0;
2535 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2536 tmp = priv->progress_widgets;
2538 /* Check all observers */
2539 while (tmp && is_empty) {
2540 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2541 is_empty = pending_ops == 0;
2543 tmp = g_slist_next(tmp);
2550 on_account_removed (TnyAccountStore *account_store,
2551 TnyAccount *account,
2554 /* Do nothing if it's a transport account, because we only
2555 show the messages of a store account */
2556 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2557 const gchar *parent_acc = NULL;
2558 const gchar *our_acc = NULL;
2560 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2561 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2563 /* Close this window if I'm showing a message of the removed account */
2564 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2565 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2570 on_mail_operation_started (ModestMailOperation *mail_op,
2573 ModestMsgViewWindow *self;
2574 ModestMailOperationTypeOperation op_type;
2576 ModestMsgViewWindowPrivate *priv;
2577 GObject *source = NULL;
2579 self = MODEST_MSG_VIEW_WINDOW (user_data);
2580 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2581 op_type = modest_mail_operation_get_type_operation (mail_op);
2582 tmp = priv->progress_widgets;
2583 source = modest_mail_operation_get_source(mail_op);
2584 if (G_OBJECT (self) == source) {
2585 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2586 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2587 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2588 set_progress_hint (self, TRUE);
2590 modest_progress_object_add_operation (
2591 MODEST_PROGRESS_OBJECT (tmp->data),
2593 tmp = g_slist_next (tmp);
2597 g_object_unref (source);
2599 /* Update dimming rules */
2600 check_dimming_rules_after_change (self);
2604 on_mail_operation_finished (ModestMailOperation *mail_op,
2607 ModestMsgViewWindow *self;
2608 ModestMailOperationTypeOperation op_type;
2610 ModestMsgViewWindowPrivate *priv;
2612 self = MODEST_MSG_VIEW_WINDOW (user_data);
2613 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2614 op_type = modest_mail_operation_get_type_operation (mail_op);
2615 tmp = priv->progress_widgets;
2617 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2618 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2619 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2621 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2623 tmp = g_slist_next (tmp);
2626 /* If no more operations are being observed, NORMAL mode is enabled again */
2627 if (observers_empty (self)) {
2628 set_progress_hint (self, FALSE);
2632 /* Update dimming rules. We have to do this right here
2633 and not in view_msg_cb because at that point the
2634 transfer mode is still enabled so the dimming rule
2635 won't let the user delete the message that has been
2636 readed for example */
2637 check_dimming_rules_after_change (self);
2641 on_queue_changed (ModestMailOperationQueue *queue,
2642 ModestMailOperation *mail_op,
2643 ModestMailOperationQueueNotification type,
2644 ModestMsgViewWindow *self)
2646 ModestMsgViewWindowPrivate *priv;
2648 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2650 /* If this operations was created by another window, do nothing */
2651 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2654 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2655 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2657 "operation-started",
2658 G_CALLBACK (on_mail_operation_started),
2660 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2662 "operation-finished",
2663 G_CALLBACK (on_mail_operation_finished),
2665 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2666 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2668 "operation-started");
2669 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2671 "operation-finished");
2676 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2678 ModestMsgViewWindowPrivate *priv;
2679 TnyList *selected_attachments = NULL;
2681 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2682 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2684 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2685 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2687 return selected_attachments;
2691 ModestMsgViewWindow *self;
2693 gchar *attachment_uid;
2694 } DecodeAsyncHelper;
2697 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2703 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2704 const gchar *content_type;
2705 ModestMsgViewWindowPrivate *priv;
2707 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2709 if (cancelled || err) {
2712 if ((err->domain == TNY_ERROR_DOMAIN) &&
2713 (err->code == TNY_IO_ERROR_WRITE) &&
2714 (errno == ENOSPC)) {
2715 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2717 msg = g_strdup (_("mail_ib_file_operation_failed"));
2719 modest_platform_information_banner (NULL, NULL, msg);
2725 /* It could happen that the window was closed. So we
2726 assume it is a cancelation */
2727 if (!GTK_WIDGET_VISIBLE (helper->self))
2730 /* Remove the progress hint */
2731 set_progress_hint (helper->self, FALSE);
2733 content_type = tny_mime_part_get_content_type (mime_part);
2734 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2735 ModestWindowMgr *mgr;
2736 ModestWindow *msg_win = NULL;
2739 const gchar *mailbox;
2740 TnyStream *file_stream;
2743 fd = g_open (helper->file_path, O_RDONLY, 0644);
2746 file_stream = tny_fs_stream_new (fd);
2748 mgr = modest_runtime_get_window_mgr ();
2750 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2751 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2754 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2756 msg = tny_camel_msg_new ();
2757 tny_camel_msg_parse (msg, file_stream);
2760 top_msg = g_object_ref (priv->top_msg);
2762 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2764 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2765 account, mailbox, helper->attachment_uid);
2766 if (top_msg) g_object_unref (top_msg);
2767 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2768 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2769 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2770 gtk_widget_show_all (GTK_WIDGET (msg_win));
2772 gtk_widget_destroy (GTK_WIDGET (msg_win));
2773 g_object_unref (msg);
2774 g_object_unref (file_stream);
2776 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2781 /* make the file read-only */
2782 g_chmod(helper->file_path, 0444);
2784 /* Activate the file */
2785 modest_platform_activate_file (helper->file_path, content_type);
2790 g_object_unref (helper->self);
2791 g_free (helper->file_path);
2792 g_free (helper->attachment_uid);
2793 g_slice_free (DecodeAsyncHelper, helper);
2797 view_attachment_connect_handler (gboolean canceled,
2799 GtkWindow *parent_window,
2800 TnyAccount *account,
2804 if (canceled || err) {
2805 g_object_unref (part);
2809 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2811 g_object_unref (part);
2815 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2816 TnyMimePart *mime_part)
2818 ModestMsgViewWindowPrivate *priv;
2819 const gchar *msg_uid;
2820 gchar *attachment_uid = NULL;
2821 gint attachment_index = 0;
2822 TnyList *attachments;
2824 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2825 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2826 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2828 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2829 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2830 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2831 g_object_unref (attachments);
2833 if (msg_uid && attachment_index >= 0) {
2834 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2837 if (mime_part == NULL) {
2838 gboolean error = FALSE;
2839 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2840 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2842 } else if (tny_list_get_length (selected_attachments) > 1) {
2843 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2847 iter = tny_list_create_iterator (selected_attachments);
2848 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2849 g_object_unref (iter);
2851 if (selected_attachments)
2852 g_object_unref (selected_attachments);
2857 g_object_ref (mime_part);
2860 if (tny_mime_part_is_purged (mime_part))
2863 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2864 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2866 TnyAccount *account;
2868 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2870 /* Get the account */
2872 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2875 if (!tny_device_is_online (modest_runtime_get_device())) {
2876 modest_platform_connect_and_perform (GTK_WINDOW (window),
2878 TNY_ACCOUNT (account),
2879 (ModestConnectedPerformer) view_attachment_connect_handler,
2880 g_object_ref (mime_part));
2885 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2886 gchar *filepath = NULL;
2887 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2888 gboolean show_error_banner = FALSE;
2889 TnyFsStream *temp_stream = NULL;
2890 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2893 if (temp_stream != NULL) {
2894 ModestAccountMgr *mgr;
2895 DecodeAsyncHelper *helper;
2896 gboolean decode_in_provider;
2897 ModestProtocol *protocol;
2898 const gchar *account;
2900 /* Activate progress hint */
2901 set_progress_hint (window, TRUE);
2903 helper = g_slice_new0 (DecodeAsyncHelper);
2904 helper->self = g_object_ref (window);
2905 helper->file_path = g_strdup (filepath);
2906 helper->attachment_uid = g_strdup (attachment_uid);
2908 decode_in_provider = FALSE;
2909 mgr = modest_runtime_get_account_mgr ();
2910 account = modest_window_get_active_account (MODEST_WINDOW (window));
2911 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2912 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2914 uri = g_strconcat ("file://", filepath, NULL);
2915 decode_in_provider =
2916 modest_account_protocol_decode_part_to_stream_async (
2917 MODEST_ACCOUNT_PROTOCOL (protocol),
2920 TNY_STREAM (temp_stream),
2921 on_decode_to_stream_async_handler,
2928 if (!decode_in_provider)
2929 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2930 on_decode_to_stream_async_handler,
2933 g_object_unref (temp_stream);
2934 /* NOTE: files in the temporary area will be automatically
2935 * cleaned after some time if they are no longer in use */
2938 const gchar *content_type;
2939 /* the file may already exist but it isn't writable,
2940 * let's try to open it anyway */
2941 content_type = tny_mime_part_get_content_type (mime_part);
2942 modest_platform_activate_file (filepath, content_type);
2944 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2945 show_error_banner = TRUE;
2950 if (show_error_banner)
2951 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2952 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2953 ModestWindowMgr *mgr;
2954 ModestWindow *msg_win = NULL;
2955 TnyMsg *current_msg;
2959 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2960 mgr = modest_runtime_get_window_mgr ();
2961 header = tny_msg_get_header (TNY_MSG (current_msg));
2962 found = modest_window_mgr_find_registered_message_uid (mgr,
2967 g_debug ("window for this body is already being created");
2971 /* it's not found, so create a new window for it */
2972 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2973 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2974 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2976 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2979 top_msg = g_object_ref (priv->top_msg);
2981 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2983 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
2984 account, mailbox, attachment_uid);
2986 if (top_msg) g_object_unref (top_msg);
2988 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2989 modest_window_get_zoom (MODEST_WINDOW (window)));
2990 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2991 gtk_widget_show_all (GTK_WIDGET (msg_win));
2993 gtk_widget_destroy (GTK_WIDGET (msg_win));
2995 g_object_unref (current_msg);
2997 /* message attachment */
2998 TnyHeader *header = NULL;
2999 ModestWindowMgr *mgr;
3000 ModestWindow *msg_win = NULL;
3003 header = tny_msg_get_header (TNY_MSG (mime_part));
3004 mgr = modest_runtime_get_window_mgr ();
3005 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3008 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3009 * thus, we don't do anything */
3010 g_debug ("window for is already being created");
3013 /* it's not found, so create a new window for it */
3014 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3015 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3016 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3018 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3020 top_msg = g_object_ref (priv->top_msg);
3022 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3023 msg_win = modest_msg_view_window_new_for_attachment (
3024 TNY_MSG (mime_part), top_msg, account,
3025 mailbox, attachment_uid);
3026 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3027 modest_window_get_zoom (MODEST_WINDOW (window)));
3028 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3029 gtk_widget_show_all (GTK_WIDGET (msg_win));
3031 gtk_widget_destroy (GTK_WIDGET (msg_win));
3037 g_free (attachment_uid);
3039 g_object_unref (mime_part);
3051 GnomeVFSResult result;
3053 ModestMsgViewWindow *window;
3056 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3057 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3058 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3059 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3062 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3066 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3067 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3068 g_free (pair->filename);
3069 g_object_unref (pair->part);
3070 g_slice_free (SaveMimePartPair, pair);
3072 g_list_free (info->pairs);
3075 g_object_unref (info->window);
3076 info->window = NULL;
3078 g_slice_free (SaveMimePartInfo, info);
3083 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3085 /* This is a GDK lock because we are an idle callback and
3086 * hildon_banner_show_information is or does Gtk+ code */
3088 gdk_threads_enter (); /* CHECKED */
3089 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3091 } else if (info->result == GNOME_VFS_OK) {
3092 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
3093 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3096 /* Check if the uri belongs to the external mmc */
3097 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3098 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3100 msg = g_strdup (_KR("cerm_memory_card_full"));
3101 modest_platform_information_banner (NULL, NULL, msg);
3104 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
3106 set_progress_hint (info->window, FALSE);
3107 save_mime_part_info_free (info, FALSE);
3108 gdk_threads_leave (); /* CHECKED */
3114 save_mime_part_to_file_connect_handler (gboolean canceled,
3116 GtkWindow *parent_window,
3117 TnyAccount *account,
3118 SaveMimePartInfo *info)
3120 if (canceled || err) {
3121 if (canceled && !err) {
3122 info->result = GNOME_VFS_ERROR_CANCELLED;
3124 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3126 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3131 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3134 TnyAccount *account;
3135 ModestMsgViewWindowPrivate *priv;
3137 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3139 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3142 /* Get the account */
3144 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3147 modest_platform_connect_and_perform (GTK_WINDOW (info->window),
3149 TNY_ACCOUNT (account),
3150 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3154 g_object_unref (account);
3160 save_mime_part_to_file (SaveMimePartInfo *info)
3162 GnomeVFSHandle *handle;
3164 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3166 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3167 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3168 gboolean check_online = TRUE;
3169 ModestMsgViewWindowPrivate *priv = NULL;
3171 /* Check if we really need to connect to save the mime part */
3172 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3173 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3174 check_online = FALSE;
3176 TnyAccountStore *acc_store;
3177 TnyAccount *account = NULL;
3179 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3180 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3183 if (tny_account_get_connection_status (account) ==
3184 TNY_CONNECTION_STATUS_CONNECTED)
3185 check_online = FALSE;
3186 g_object_unref (account);
3188 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3193 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3198 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3199 if (info->result == GNOME_VFS_OK) {
3200 GError *error = NULL;
3201 gboolean decode_in_provider;
3203 ModestAccountMgr *mgr;
3204 const gchar *account;
3205 ModestProtocol *protocol = NULL;
3207 stream = tny_vfs_stream_new (handle);
3209 decode_in_provider = FALSE;
3210 mgr = modest_runtime_get_account_mgr ();
3211 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3212 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3213 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3214 decode_in_provider =
3215 modest_account_protocol_decode_part_to_stream (
3216 MODEST_ACCOUNT_PROTOCOL (protocol),
3224 if (!decode_in_provider)
3225 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3228 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3230 if (error && (error->domain == TNY_ERROR_DOMAIN) &&
3231 (error->code == TNY_IO_ERROR_WRITE) &&
3232 (errno == ENOSPC)) {
3233 info->result = GNOME_VFS_ERROR_NO_SPACE;
3235 info->result = GNOME_VFS_ERROR_IO;
3238 g_object_unref (G_OBJECT (stream));
3240 g_warning ("Could not create save attachment %s: %s\n",
3241 pair->filename, gnome_vfs_result_to_string (info->result));
3244 /* Go on saving remaining files */
3245 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3246 if (info->pairs != NULL) {
3247 save_mime_part_to_file (info);
3249 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3256 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3257 SaveMimePartInfo *info)
3259 gboolean is_ok = TRUE;
3260 gint replaced_files = 0;
3261 const GList *files = info->pairs;
3262 const GList *iter, *to_replace = NULL;
3264 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3265 SaveMimePartPair *pair = iter->data;
3266 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3268 if (modest_utils_file_exists (unescaped)) {
3270 if (replaced_files == 1)
3275 if (replaced_files) {
3278 if (replaced_files == 1) {
3279 SaveMimePartPair *pair = to_replace->data;
3280 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3281 gchar *escaped_basename, *message;
3283 escaped_basename = g_uri_unescape_string (basename, NULL);
3284 message = g_strdup_printf ("%s\n%s",
3285 _FM("docm_nc_replace_file"),
3286 (escaped_basename) ? escaped_basename : "");
3287 response = modest_platform_run_confirmation_dialog (parent, message);
3289 g_free (escaped_basename);
3291 response = modest_platform_run_confirmation_dialog (parent,
3292 _FM("docm_nc_replace_multiple"));
3294 if (response != GTK_RESPONSE_OK)
3299 save_mime_part_info_free (info, TRUE);
3301 /* Start progress and launch thread */
3302 set_progress_hint (info->window, TRUE);
3303 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3308 typedef struct _SaveAttachmentsInfo {
3309 TnyList *attachments_list;
3310 ModestMsgViewWindow *window;
3311 } SaveAttachmentsInfo;
3314 save_attachments_response (GtkDialog *dialog,
3318 TnyList *mime_parts;
3320 GList *files_to_save = NULL;
3321 gchar *current_folder;
3322 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3324 mime_parts = TNY_LIST (sa_info->attachments_list);
3326 if (arg1 != GTK_RESPONSE_OK)
3329 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3330 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3331 if (current_folder && *current_folder != '\0') {
3333 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3334 current_folder,&err);
3336 g_debug ("Error storing latest used folder: %s", err->message);
3340 g_free (current_folder);
3342 if (!modest_utils_folder_writable (chooser_uri)) {
3343 const gchar *err_msg;
3345 #ifdef MODEST_PLATFORM_MAEMO
3346 if (modest_maemo_utils_in_usb_mode ()) {
3347 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3349 err_msg = _FM("sfil_ib_readonly_location");
3352 err_msg = _FM("sfil_ib_readonly_location");
3354 hildon_banner_show_information (NULL, NULL, err_msg);
3358 iter = tny_list_create_iterator (mime_parts);
3359 while (!tny_iterator_is_done (iter)) {
3360 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3362 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3363 !tny_mime_part_is_purged (mime_part) &&
3364 (tny_mime_part_get_filename (mime_part) != NULL)) {
3365 SaveMimePartPair *pair;
3367 pair = g_slice_new0 (SaveMimePartPair);
3369 if (tny_list_get_length (mime_parts) > 1) {
3371 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3372 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3375 pair->filename = g_strdup (chooser_uri);
3377 pair->part = mime_part;
3378 files_to_save = g_list_prepend (files_to_save, pair);
3380 tny_iterator_next (iter);
3382 g_object_unref (iter);
3385 if (files_to_save != NULL) {
3386 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3387 info->pairs = files_to_save;
3388 info->result = TRUE;
3389 info->uri = g_strdup (chooser_uri);
3390 info->window = g_object_ref (sa_info->window);
3391 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3393 g_free (chooser_uri);
3396 /* Free and close the dialog */
3397 g_object_unref (mime_parts);
3398 g_object_unref (sa_info->window);
3399 g_slice_free (SaveAttachmentsInfo, sa_info);
3400 gtk_widget_destroy (GTK_WIDGET (dialog));
3404 msg_is_attachment (TnyList *mime_parts)
3407 gboolean retval = FALSE;
3409 if (tny_list_get_length (mime_parts) > 1)
3412 iter = tny_list_create_iterator (mime_parts);
3414 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3416 if (TNY_IS_MSG (part))
3418 g_object_unref (part);
3420 g_object_unref (iter);
3426 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3427 TnyList *mime_parts)
3429 ModestMsgViewWindowPrivate *priv;
3430 GtkWidget *save_dialog = NULL;
3431 gchar *conf_folder = NULL;
3432 gchar *filename = NULL;
3433 gchar *save_multiple_str = NULL;
3434 const gchar *root_folder = "file:///";
3436 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3437 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3439 if (mime_parts == NULL) {
3440 gboolean allow_msgs = FALSE;
3442 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3443 * selection available */
3444 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3446 /* Check if the message is composed by an unique MIME
3447 part whose content disposition is attachment. There
3448 could be messages like this:
3450 Date: Tue, 12 Jan 2010 20:40:59 +0000
3451 From: <sender@example.org>
3452 To: <recipient@example.org>
3454 Content-Type: image/jpeg
3455 Content-Disposition: attachment; filename="bug7718.jpeg"
3457 whose unique MIME part is the message itself whose
3458 content disposition is attachment
3460 if (mime_parts && msg_is_attachment (mime_parts))
3464 !modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, allow_msgs)) {
3465 g_object_unref (mime_parts);
3468 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3470 g_object_unref (mime_parts);
3476 g_object_ref (mime_parts);
3479 /* prepare dialog */
3480 if (tny_list_get_length (mime_parts) == 1) {
3482 /* only one attachment selected */
3483 iter = tny_list_create_iterator (mime_parts);
3484 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3485 g_object_unref (iter);
3486 if (!modest_tny_mime_part_is_msg (mime_part) &&
3487 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3488 !tny_mime_part_is_purged (mime_part)) {
3489 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3491 /* TODO: show any error? */
3492 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3493 g_object_unref (mime_parts);
3496 g_object_unref (mime_part);
3498 gint num = tny_list_get_length (mime_parts);
3499 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3500 "sfil_va_number_of_objects_attachment",
3501 "sfil_va_number_of_objects_attachments",
3505 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
3506 GTK_FILE_CHOOSER_ACTION_SAVE);
3508 /* Get last used folder */
3509 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3510 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3512 /* File chooser stops working if we select "file:///" as current folder */
3513 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3514 g_free (conf_folder);
3518 if (conf_folder && conf_folder[0] != '\0') {
3519 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3522 /* Set the default folder to documents folder */
3523 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3526 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3528 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3529 g_free (docs_folder);
3531 g_free (conf_folder);
3535 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3540 /* if multiple, set multiple string */
3541 if (save_multiple_str) {
3542 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3543 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
3544 g_free (save_multiple_str);
3547 /* We must run this asynchronously, because the hildon dialog
3548 performs a gtk_dialog_run by itself which leads to gdk
3550 SaveAttachmentsInfo *sa_info;
3551 sa_info = g_slice_new (SaveAttachmentsInfo);
3552 sa_info->attachments_list = mime_parts;
3553 sa_info->window = g_object_ref (window);
3554 g_signal_connect (save_dialog, "response",
3555 G_CALLBACK (save_attachments_response), sa_info);
3557 gtk_widget_show_all (save_dialog);
3561 show_remove_attachment_information (gpointer userdata)
3563 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3564 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3566 /* We're outside the main lock */
3567 gdk_threads_enter ();
3569 if (priv->remove_attachment_banner != NULL) {
3570 gtk_widget_destroy (priv->remove_attachment_banner);
3571 g_object_unref (priv->remove_attachment_banner);
3574 priv->remove_attachment_banner = g_object_ref (
3575 hildon_banner_show_animation (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3577 gdk_threads_leave ();
3583 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3585 ModestMsgViewWindowPrivate *priv;
3586 TnyList *mime_parts = NULL, *tmp;
3587 gchar *confirmation_message;
3593 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3594 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3596 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3597 * because we don't have selection
3599 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3601 /* Remove already purged messages from mime parts list. We use
3602 a copy of the list to remove items in the original one */
3603 tmp = tny_list_copy (mime_parts);
3604 iter = tny_list_create_iterator (tmp);
3605 while (!tny_iterator_is_done (iter)) {
3606 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3607 if (tny_mime_part_is_purged (part))
3608 tny_list_remove (mime_parts, (GObject *) part);
3610 g_object_unref (part);
3611 tny_iterator_next (iter);
3613 g_object_unref (tmp);
3614 g_object_unref (iter);
3616 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3617 tny_list_get_length (mime_parts) == 0) {
3618 g_object_unref (mime_parts);
3622 n_attachments = tny_list_get_length (mime_parts);
3623 if (n_attachments == 1) {
3627 iter = tny_list_create_iterator (mime_parts);
3628 part = (TnyMimePart *) tny_iterator_get_current (iter);
3629 g_object_unref (iter);
3630 if (modest_tny_mime_part_is_msg (part)) {
3632 header = tny_msg_get_header (TNY_MSG (part));
3633 filename = tny_header_dup_subject (header);
3634 g_object_unref (header);
3635 if (filename == NULL)
3636 filename = g_strdup (_("mail_va_no_subject"));
3638 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3640 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3642 g_object_unref (part);
3644 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3645 "mcen_nc_purge_files_text",
3646 n_attachments), n_attachments);
3648 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3649 confirmation_message);
3650 g_free (confirmation_message);
3652 if (response != GTK_RESPONSE_OK) {
3653 g_object_unref (mime_parts);
3657 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3659 iter = tny_list_create_iterator (mime_parts);
3660 while (!tny_iterator_is_done (iter)) {
3663 part = (TnyMimePart *) tny_iterator_get_current (iter);
3664 tny_mime_part_set_purged (TNY_MIME_PART (part));
3665 g_object_unref (part);
3666 tny_iterator_next (iter);
3668 g_object_unref (iter);
3670 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3671 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3672 tny_msg_rewrite_cache (msg);
3673 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3674 g_object_unref (msg);
3675 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3677 g_object_unref (mime_parts);
3679 if (priv->purge_timeout > 0) {
3680 g_source_remove (priv->purge_timeout);
3681 priv->purge_timeout = 0;
3684 if (priv->remove_attachment_banner) {
3685 gtk_widget_destroy (priv->remove_attachment_banner);
3686 g_object_unref (priv->remove_attachment_banner);
3687 priv->remove_attachment_banner = NULL;
3693 update_window_title (ModestMsgViewWindow *window)
3695 ModestMsgViewWindowPrivate *priv;
3697 TnyHeader *header = NULL;
3698 gchar *subject = NULL;
3700 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3702 /* Note that if the window is closed while we're retrieving
3703 the message, this widget could de deleted */
3704 if (!priv->msg_view)
3707 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3709 if (priv->other_body) {
3712 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3714 g_strstrip (description);
3715 subject = description;
3717 } else if (msg != NULL) {
3718 header = tny_msg_get_header (msg);
3719 subject = tny_header_dup_subject (header);
3720 g_object_unref (header);
3721 g_object_unref (msg);
3724 if ((subject == NULL)||(subject[0] == '\0')) {
3726 subject = g_strdup (_("mail_va_no_subject"));
3729 gtk_window_set_title (GTK_WINDOW (window), subject);
3734 on_move_focus (GtkWidget *widget,
3735 GtkDirectionType direction,
3738 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3742 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3744 GnomeVFSResult result;
3745 GnomeVFSHandle *handle = NULL;
3746 GnomeVFSFileInfo *info = NULL;
3749 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3750 if (result != GNOME_VFS_OK) {
3755 info = gnome_vfs_file_info_new ();
3756 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3757 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3758 /* We put a "safe" default size for going to cache */
3759 *expected_size = (300*1024);
3761 *expected_size = info->size;
3763 gnome_vfs_file_info_unref (info);
3765 stream = tny_vfs_stream_new (handle);
3774 TnyStream *output_stream;
3775 GtkWidget *msg_view;
3780 on_fetch_image_timeout_refresh_view (gpointer userdata)
3782 ModestMsgViewWindowPrivate *priv;
3784 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3785 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3786 /* Note that priv->msg_view is set to NULL when this window is
3788 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3789 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3791 priv->fetch_image_redraw_handler = 0;
3792 g_object_unref (userdata);
3797 on_fetch_image_idle_refresh_view (gpointer userdata)
3800 FetchImageData *fidata = (FetchImageData *) userdata;
3802 gdk_threads_enter ();
3803 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3804 ModestMsgViewWindowPrivate *priv;
3806 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3807 priv->fetching_images--;
3808 if (priv->fetch_image_redraw_handler == 0) {
3809 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3813 gdk_threads_leave ();
3815 g_object_unref (fidata->msg_view);
3816 g_object_unref (fidata->window);
3817 g_slice_free (FetchImageData, fidata);
3822 on_fetch_image_thread (gpointer userdata)
3824 FetchImageData *fidata = (FetchImageData *) userdata;
3825 TnyStreamCache *cache;
3826 TnyStream *cache_stream;
3828 cache = modest_runtime_get_images_cache ();
3830 tny_stream_cache_get_stream (cache,
3832 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3833 (gpointer) fidata->uri);
3834 g_free (fidata->cache_id);
3835 g_free (fidata->uri);
3837 if (cache_stream != NULL) {
3840 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3843 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3844 if (G_UNLIKELY (nb_read < 0)) {
3846 } else if (G_LIKELY (nb_read > 0)) {
3847 gssize nb_written = 0;
3849 while (G_UNLIKELY (nb_written < nb_read)) {
3852 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3853 nb_read - nb_written);
3854 if (G_UNLIKELY (len < 0))
3860 tny_stream_close (cache_stream);
3861 g_object_unref (cache_stream);
3864 tny_stream_close (fidata->output_stream);
3865 g_object_unref (fidata->output_stream);
3867 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3873 on_fetch_image (ModestMsgView *msgview,
3876 ModestMsgViewWindow *window)
3878 const gchar *current_account;
3879 ModestMsgViewWindowPrivate *priv;
3880 FetchImageData *fidata;
3882 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3884 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3886 fidata = g_slice_new0 (FetchImageData);
3887 fidata->msg_view = g_object_ref (msgview);
3888 fidata->window = g_object_ref (window);
3889 fidata->uri = g_strdup (uri);
3890 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3891 fidata->output_stream = g_object_ref (stream);
3893 priv->fetching_images++;
3894 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3895 g_object_unref (fidata->output_stream);
3896 g_free (fidata->cache_id);
3897 g_free (fidata->uri);
3898 g_object_unref (fidata->msg_view);
3899 g_slice_free (FetchImageData, fidata);
3900 tny_stream_close (stream);
3901 priv->fetching_images--;
3902 update_progress_hint (window);
3905 update_progress_hint (window);
3911 setup_menu (ModestMsgViewWindow *self)
3913 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3915 /* Settings menu buttons */
3916 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3917 APP_MENU_CALLBACK (modest_msg_view_window_show_find_toolbar),
3918 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3920 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self),
3921 dngettext(GETTEXT_PACKAGE,
3922 "mcen_me_move_message",
3923 "mcen_me_move_messages",
3926 APP_MENU_CALLBACK (modest_ui_actions_on_move_to),
3927 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3929 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3930 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3931 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3933 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3934 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3935 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3937 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3938 APP_MENU_CALLBACK (modest_ui_actions_save_attachments),
3939 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3940 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3941 APP_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3942 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3944 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3945 APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3946 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3947 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3948 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3949 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3951 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3952 APP_MENU_CALLBACK (modest_ui_actions_on_details),
3953 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3957 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3959 ModestMsgViewWindowPrivate *priv;
3960 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3961 GSList *recipients = NULL;
3964 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3968 header = modest_msg_view_window_get_header (self);
3971 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3972 g_object_unref (header);
3974 recipients = modest_tny_msg_get_all_recipients_list (msg);
3975 g_object_unref (msg);
3979 /* Offer the user to add recipients to the address book */
3980 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
3981 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
3986 _modest_msg_view_window_map_event (GtkWidget *widget,
3990 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
3992 update_progress_hint (self);
3998 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4000 ModestMsgViewWindowPrivate *priv;
4001 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4003 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4007 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4009 ModestMsgViewWindowPrivate *priv;
4010 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4012 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4014 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4018 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4020 ModestMsgViewWindowPrivate *priv;
4021 const gchar *msg_uid;
4022 TnyHeader *header = NULL;
4023 TnyFolder *folder = NULL;
4025 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4027 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4029 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4033 folder = tny_header_get_folder (header);
4034 g_object_unref (header);
4039 msg_uid = modest_msg_view_window_get_message_uid (self);
4041 GtkTreeRowReference *row_reference;
4043 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4044 row_reference = priv->row_reference;
4046 row_reference = NULL;
4048 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4049 g_warning ("Shouldn't happen, trying to reload a message failed");
4052 g_object_unref (folder);
4056 update_branding (ModestMsgViewWindow *self)
4058 const gchar *account;
4059 const gchar *mailbox;
4060 ModestAccountMgr *mgr;
4061 ModestProtocol *protocol = NULL;
4062 gchar *service_name = NULL;
4063 const GdkPixbuf *service_icon = NULL;
4064 ModestMsgViewWindowPrivate *priv;
4066 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4068 account = modest_window_get_active_account (MODEST_WINDOW (self));
4069 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4071 mgr = modest_runtime_get_account_mgr ();
4073 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4074 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4075 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4077 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4078 account, mailbox, MODEST_ICON_SIZE_SMALL);
4082 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4083 g_free (service_name);
4087 sync_flags (ModestMsgViewWindow *self)
4089 TnyHeader *header = NULL;
4091 header = modest_msg_view_window_get_header (self);
4093 TnyMsg *msg = modest_msg_view_window_get_message (self);
4095 header = tny_msg_get_header (msg);
4096 g_object_unref (msg);
4101 TnyFolder *folder = tny_header_get_folder (header);
4104 ModestMailOperation *mail_op;
4106 /* Sync folder, we need this to save the seen flag */
4107 mail_op = modest_mail_operation_new (NULL);
4108 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4110 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4111 g_object_unref (mail_op);
4112 g_object_unref (folder);
4114 g_object_unref (header);
4119 on_realize (GtkWidget *widget,
4122 GdkDisplay *display;
4124 unsigned long val = 1;
4126 display = gdk_drawable_get_display (widget->window);
4127 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4128 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4129 GDK_WINDOW_XID (widget->window), atom,
4130 XA_INTEGER, 32, PropModeReplace,
4131 (unsigned char *) &val, 1);
4137 on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
4139 const gchar *account_name;
4140 ModestProtocolType proto_type;
4141 ModestProtocol *protocol;
4142 gboolean retval = FALSE;
4144 account_name = modest_window_get_active_account (MODEST_WINDOW (self));
4147 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
4150 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
4153 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4154 retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
4155 calendar_part, container);