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