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-toolkit-utils.h>
41 #include <modest-tny-msg.h>
42 #include <modest-msg-view-window.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-progress-object.h>
46 #include <modest-runtime.h>
47 #include <modest-window-priv.h>
48 #include <modest-tny-folder.h>
49 #include <modest-text-utils.h>
50 #include <modest-account-mgr-helpers.h>
51 #include <modest-toolkit-factory.h>
52 #include <modest-scrollable.h>
53 #include <modest-isearch-toolbar.h>
54 #include "modest-defs.h"
55 #include "modest-ui-dimming-manager.h"
56 #include <gdk/gdkkeysyms.h>
57 #include <modest-tny-account.h>
58 #include <modest-mime-part-view.h>
59 #include <modest-isearch-view.h>
60 #include <modest-tny-mime-part.h>
61 #include <modest-address-book.h>
64 #include <glib/gstdio.h>
65 #include <modest-debug.h>
66 #include <modest-header-window.h>
67 #include <modest-account-protocol.h>
68 #include <modest-icon-names.h>
69 #include <modest-ui-actions.h>
70 #include <modest-window-mgr.h>
71 #include <tny-camel-msg.h>
72 #include <modest-icon-names.h>
74 #ifdef MODEST_PLATFORM_MAEMO
75 #include <modest-maemo-utils.h>
78 #ifdef MODEST_TOOLKIT_HILDON2
79 #include <hildon/hildon.h>
81 #include <X11/Xatom.h>
82 #include <X11/XKBlib.h>
83 #include <X11/Xdmcp.h>
86 #include <tny-camel-bs-mime-part.h>
87 #include <tny-camel-bs-msg.h>
89 #define MYDOCS_ENV "MYDOCSDIR"
90 #define DOCS_FOLDER ".documents"
92 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
93 struct _ModestMsgViewWindowPrivate {
96 GtkWidget *main_scroll;
97 GtkWidget *isearch_toolbar;
100 /* Progress observers */
101 GSList *progress_widgets;
104 GtkWidget *prev_toolitem;
105 GtkWidget *next_toolitem;
106 gboolean progress_hint;
107 gint fetching_images;
109 /* Optimized view enabled */
110 gboolean optimized_view;
112 /* Whether this was created via the *_new_for_search_result() function. */
113 gboolean is_search_result;
115 /* Whether the message is in outbox */
118 /* A reference to the @model of the header view
119 * to allow selecting previous/next messages,
120 * if the message is currently selected in the header view.
122 const gchar *header_folder_id;
123 GtkTreeModel *header_model;
124 GtkTreeRowReference *row_reference;
125 GtkTreeRowReference *next_row_reference;
127 gulong clipboard_change_handler;
128 gulong queue_change_handler;
129 gulong account_removed_handler;
130 gulong row_changed_handler;
131 gulong row_deleted_handler;
132 gulong row_inserted_handler;
133 gulong rows_reordered_handler;
134 gulong fetch_image_redraw_handler;
137 GtkWidget *remove_attachment_banner;
140 TnyMimePart *other_body;
146 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
147 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
148 static void modest_header_view_observer_init (ModestHeaderViewObserverIface *iface_class);
149 static void modest_msg_view_window_finalize (GObject *obj);
150 static void modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj, gpointer data);
151 static void modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
152 ModestMsgViewWindow *obj);
153 static void modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
154 ModestMsgViewWindow *obj);
155 static void modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
157 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
159 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
160 static void modest_msg_view_window_set_zoom (ModestWindow *window,
162 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
163 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
164 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
167 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
169 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
170 gboolean show_toolbar);
172 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
174 ModestMsgViewWindow *window);
176 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
179 ModestMsgViewWindow *window);
181 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
183 ModestMsgViewWindow *window);
185 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
186 GtkTreePath *tree_path,
187 GtkTreeIter *tree_iter,
188 ModestMsgViewWindow *window);
190 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
194 ModestMsgViewWindow *window);
196 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
198 const gchar *tny_folder_id);
200 static void on_queue_changed (ModestMailOperationQueue *queue,
201 ModestMailOperation *mail_op,
202 ModestMailOperationQueueNotification type,
203 ModestMsgViewWindow *self);
205 static void on_account_removed (TnyAccountStore *account_store,
209 static void on_move_focus (GtkWidget *widget,
210 GtkDirectionType direction,
213 static void view_msg_cb (ModestMailOperation *mail_op,
220 static void set_progress_hint (ModestMsgViewWindow *self,
223 static void update_window_title (ModestMsgViewWindow *window);
225 static void init_window (ModestMsgViewWindow *obj);
227 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
229 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
231 static gboolean on_fetch_image (ModestMsgView *msgview,
234 ModestMsgViewWindow *window);
236 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
237 GtkScrollType scroll_type,
240 static gboolean message_reader (ModestMsgViewWindow *window,
241 ModestMsgViewWindowPrivate *priv,
243 const gchar *msg_uid,
245 GtkTreeRowReference *row_reference);
247 static void setup_menu (ModestMsgViewWindow *self);
248 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
251 static void update_branding (ModestMsgViewWindow *self);
252 static void sync_flags (ModestMsgViewWindow *self);
253 static gboolean on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part,
254 GtkContainer *container, ModestMsgViewWindow *self);
256 static gboolean on_realize (GtkWidget *widget,
259 /* list my signals */
266 static const GtkActionEntry msg_view_toolbar_action_entries [] = {
269 { "ToolbarMessageReply", MODEST_STOCK_REPLY, N_("mcen_me_inbox_reply"), "<CTRL>R", NULL, G_CALLBACK (modest_ui_actions_on_reply) },
270 { "ToolbarMessageReplyAll", MODEST_STOCK_REPLY_ALL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
271 { "ToolbarMessageForward", MODEST_STOCK_FORWARD, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
272 { "ToolbarDeleteMessage", MODEST_STOCK_DELETE, N_("qgn_toolb_gene_deletebutton"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message_or_folder) },
273 { "ToolbarMessageBack", MODEST_TOOLBAR_ICON_PREV, N_("qgn_toolb_gene_back"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_prev) },
274 { "ToolbarMessageNext", MODEST_TOOLBAR_ICON_NEXT, N_("qgn_toolb_gene_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_next) },
275 { "ToolbarDownloadExternalImages", MODEST_TOOLBAR_ICON_DOWNLOAD_IMAGES, N_("mail_bd_external_images"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_fetch_images) },
278 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
279 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_isearch_toolbar), FALSE },
282 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
283 MODEST_TYPE_MSG_VIEW_WINDOW, \
284 ModestMsgViewWindowPrivate))
286 static ModestWindowParentClass *parent_class = NULL;
288 /* uncomment the following if you have defined any signals */
289 static guint signals[LAST_SIGNAL] = {0};
292 modest_msg_view_window_get_type (void)
294 static GType my_type = 0;
296 static const GTypeInfo my_info = {
297 sizeof(ModestMsgViewWindowClass),
298 NULL, /* base init */
299 NULL, /* base finalize */
300 (GClassInitFunc) modest_msg_view_window_class_init,
301 NULL, /* class finalize */
302 NULL, /* class data */
303 sizeof(ModestMsgViewWindow),
305 (GInstanceInitFunc) modest_msg_view_window_init,
308 #ifndef MODEST_TOOLKIT_HILDON2
309 my_type = g_type_register_static (MODEST_TYPE_SHELL_WINDOW,
310 "ModestMsgViewWindow",
313 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
314 "ModestMsgViewWindow",
318 static const GInterfaceInfo modest_header_view_observer_info =
320 (GInterfaceInitFunc) modest_header_view_observer_init,
321 NULL, /* interface_finalize */
322 NULL /* interface_data */
325 g_type_add_interface_static (my_type,
326 MODEST_TYPE_HEADER_VIEW_OBSERVER,
327 &modest_header_view_observer_info);
333 save_state (ModestWindow *self)
335 modest_widget_memory_save (modest_runtime_get_conf (),
337 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
341 modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
342 GtkScrollType scroll_type,
346 ModestMsgViewWindowPrivate *priv;
349 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
351 switch (scroll_type) {
352 case GTK_SCROLL_STEP_UP:
355 case GTK_SCROLL_STEP_DOWN:
358 case GTK_SCROLL_PAGE_UP:
361 case GTK_SCROLL_PAGE_DOWN:
364 case GTK_SCROLL_START:
375 modest_scrollable_scroll ((ModestScrollable *) priv->main_scroll, 0, step);
377 return (gboolean) step;
381 add_scroll_binding (GtkBindingSet *binding_set,
383 GtkScrollType scroll)
385 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
387 gtk_binding_entry_add_signal (binding_set, keyval, 0,
389 GTK_TYPE_SCROLL_TYPE, scroll,
390 G_TYPE_BOOLEAN, FALSE);
391 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
393 GTK_TYPE_SCROLL_TYPE, scroll,
394 G_TYPE_BOOLEAN, FALSE);
398 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
400 GObjectClass *gobject_class;
401 ModestWindowClass *modest_window_class;
402 GtkBindingSet *binding_set;
404 gobject_class = (GObjectClass*) klass;
405 modest_window_class = (ModestWindowClass *) klass;
407 parent_class = g_type_class_peek_parent (klass);
408 gobject_class->finalize = modest_msg_view_window_finalize;
410 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
411 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
412 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
413 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
414 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
415 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
417 modest_window_class->save_state_func = save_state;
419 klass->scroll_child = modest_msg_view_window_scroll_child;
421 signals[MSG_CHANGED_SIGNAL] =
422 g_signal_new ("msg-changed",
423 G_TYPE_FROM_CLASS (gobject_class),
425 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
427 modest_marshal_VOID__POINTER_POINTER,
428 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
430 signals[SCROLL_CHILD_SIGNAL] =
431 g_signal_new ("scroll-child",
432 G_TYPE_FROM_CLASS (gobject_class),
433 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
434 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
436 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
437 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
439 binding_set = gtk_binding_set_by_class (klass);
440 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
441 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
442 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
443 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
444 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
445 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
447 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
451 static void modest_header_view_observer_init(
452 ModestHeaderViewObserverIface *iface_class)
454 iface_class->update_func = modest_msg_view_window_update_model_replaced;
458 modest_msg_view_window_init (ModestMsgViewWindow *obj)
460 ModestMsgViewWindowPrivate *priv;
461 ModestWindowPrivate *parent_priv = NULL;
462 GtkActionGroup *action_group = NULL;
463 GError *error = NULL;
465 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
466 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
467 parent_priv->ui_manager = gtk_ui_manager_new();
469 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
470 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
472 /* Add common actions */
473 gtk_action_group_add_actions (action_group,
474 msg_view_toolbar_action_entries,
475 G_N_ELEMENTS (msg_view_toolbar_action_entries),
477 gtk_action_group_add_toggle_actions (action_group,
478 msg_view_toggle_action_entries,
479 G_N_ELEMENTS (msg_view_toggle_action_entries),
482 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
483 g_object_unref (action_group);
485 /* Load the UI definition */
486 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
489 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
490 g_error_free (error);
494 priv->is_search_result = FALSE;
495 priv->is_outbox = FALSE;
497 priv->msg_view = NULL;
498 priv->header_model = NULL;
499 priv->header_folder_id = NULL;
500 priv->clipboard_change_handler = 0;
501 priv->queue_change_handler = 0;
502 priv->account_removed_handler = 0;
503 priv->row_changed_handler = 0;
504 priv->row_deleted_handler = 0;
505 priv->row_inserted_handler = 0;
506 priv->rows_reordered_handler = 0;
507 priv->fetch_image_redraw_handler = 0;
508 priv->progress_hint = FALSE;
509 priv->fetching_images = 0;
511 priv->optimized_view = FALSE;
512 priv->purge_timeout = 0;
513 priv->remove_attachment_banner = NULL;
514 priv->msg_uid = NULL;
515 priv->other_body = NULL;
517 priv->sighandlers = NULL;
520 init_window (MODEST_MSG_VIEW_WINDOW(obj));
522 #ifdef MODEST_TOOLKIT_HILDON2
523 /* Grab the zoom keys, it will be used for Zoom and not for
525 g_signal_connect (G_OBJECT (obj), "realize",
526 G_CALLBACK (on_realize),
532 update_progress_hint (ModestMsgViewWindow *self)
534 ModestMsgViewWindowPrivate *priv;
535 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
537 if (GTK_WIDGET_VISIBLE (self)) {
538 modest_window_show_progress (MODEST_WINDOW (self),
539 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
544 set_progress_hint (ModestMsgViewWindow *self,
547 ModestWindowPrivate *parent_priv;
548 ModestMsgViewWindowPrivate *priv;
550 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
552 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
553 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
555 /* Sets current progress hint */
556 priv->progress_hint = enabled;
558 update_progress_hint (self);
564 init_window (ModestMsgViewWindow *obj)
566 GtkWidget *main_vbox;
567 ModestMsgViewWindowPrivate *priv;
569 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
571 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
572 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
573 main_vbox = gtk_vbox_new (FALSE, 6);
575 priv->main_scroll = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
576 modest_scrollable_set_horizontal_policy (MODEST_SCROLLABLE (priv->main_scroll), GTK_POLICY_AUTOMATIC);
577 g_object_set (G_OBJECT (priv->main_scroll),
578 "movement-mode", MODEST_MOVEMENT_MODE_BOTH,
579 "horizontal-max-overshoot", 0,
581 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
582 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
583 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
585 /* NULL-ize fields if the window is destroyed */
586 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
588 gtk_widget_show_all (GTK_WIDGET(main_vbox));
592 modest_msg_view_window_disconnect_signals (ModestWindow *self)
594 ModestMsgViewWindowPrivate *priv;
595 GtkWidget *header_view = NULL;
596 GtkWindow *parent_window = NULL;
598 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
600 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
601 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
602 priv->clipboard_change_handler))
603 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
604 priv->clipboard_change_handler);
606 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
607 priv->queue_change_handler))
608 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
609 priv->queue_change_handler);
611 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
612 priv->account_removed_handler))
613 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
614 priv->account_removed_handler);
616 if (priv->header_model) {
617 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
618 priv->row_changed_handler))
619 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
620 priv->row_changed_handler);
622 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
623 priv->row_deleted_handler))
624 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
625 priv->row_deleted_handler);
627 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
628 priv->row_inserted_handler))
629 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
630 priv->row_inserted_handler);
632 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
633 priv->rows_reordered_handler))
634 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
635 priv->rows_reordered_handler);
638 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
639 priv->sighandlers = NULL;
641 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
642 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
643 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
645 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
646 MODEST_HEADER_VIEW_OBSERVER(self));
652 modest_msg_view_window_finalize (GObject *obj)
654 ModestMsgViewWindowPrivate *priv;
656 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
658 /* Sanity check: shouldn't be needed, the window mgr should
659 call this function before */
660 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
662 if (priv->fetch_image_redraw_handler > 0) {
663 g_source_remove (priv->fetch_image_redraw_handler);
664 priv->fetch_image_redraw_handler = 0;
667 if (priv->other_body != NULL) {
668 g_object_unref (priv->other_body);
669 priv->other_body = NULL;
672 if (priv->top_msg != NULL) {
673 g_object_unref (priv->top_msg);
674 priv->top_msg = NULL;
677 if (priv->header_model != NULL) {
678 g_object_unref (priv->header_model);
679 priv->header_model = NULL;
682 if (priv->remove_attachment_banner) {
683 gtk_widget_destroy (priv->remove_attachment_banner);
684 g_object_unref (priv->remove_attachment_banner);
685 priv->remove_attachment_banner = NULL;
688 if (priv->purge_timeout > 0) {
689 g_source_remove (priv->purge_timeout);
690 priv->purge_timeout = 0;
693 if (priv->row_reference) {
694 gtk_tree_row_reference_free (priv->row_reference);
695 priv->row_reference = NULL;
698 if (priv->next_row_reference) {
699 gtk_tree_row_reference_free (priv->next_row_reference);
700 priv->next_row_reference = NULL;
704 g_free (priv->msg_uid);
705 priv->msg_uid = NULL;
708 G_OBJECT_CLASS(parent_class)->finalize (obj);
712 select_next_valid_row (GtkTreeModel *model,
713 GtkTreeRowReference **row_reference,
717 GtkTreeIter tmp_iter;
719 GtkTreePath *next = NULL;
720 gboolean retval = FALSE, finished;
722 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
724 path = gtk_tree_row_reference_get_path (*row_reference);
725 gtk_tree_model_get_iter (model, &tmp_iter, path);
726 gtk_tree_row_reference_free (*row_reference);
727 *row_reference = NULL;
731 TnyHeader *header = NULL;
733 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
734 gtk_tree_model_get (model, &tmp_iter,
735 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
739 if (msg_is_visible (header, is_outbox)) {
740 next = gtk_tree_model_get_path (model, &tmp_iter);
741 *row_reference = gtk_tree_row_reference_new (model, next);
742 gtk_tree_path_free (next);
746 g_object_unref (header);
749 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
750 next = gtk_tree_model_get_path (model, &tmp_iter);
752 /* Ensure that we are not selecting the same */
753 if (gtk_tree_path_compare (path, next) != 0) {
754 gtk_tree_model_get (model, &tmp_iter,
755 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
758 if (msg_is_visible (header, is_outbox)) {
759 *row_reference = gtk_tree_row_reference_new (model, next);
763 g_object_unref (header);
767 /* If we ended up in the same message
768 then there is no valid next
772 gtk_tree_path_free (next);
774 /* If there are no more messages and we don't
775 want to start again in the first one then
776 there is no valid next message */
782 gtk_tree_path_free (path);
787 /* TODO: This should be in _init(), with the parameters as properties. */
789 modest_msg_view_window_construct (ModestMsgViewWindow *self,
790 const gchar *modest_account_name,
791 const gchar *mailbox,
792 const gchar *msg_uid)
795 ModestMsgViewWindowPrivate *priv = NULL;
796 ModestWindowPrivate *parent_priv = NULL;
797 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
798 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
800 obj = G_OBJECT (self);
801 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
802 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
804 priv->msg_uid = g_strdup (msg_uid);
807 parent_priv->menubar = NULL;
809 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
810 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
813 /* Add common dimming rules */
814 modest_dimming_rules_group_add_rules (toolbar_rules_group,
815 modest_msg_view_toolbar_dimming_entries,
816 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
817 MODEST_WINDOW (self));
818 modest_dimming_rules_group_add_rules (clipboard_rules_group,
819 modest_msg_view_clipboard_dimming_entries,
820 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
821 MODEST_WINDOW (self));
823 /* Insert dimming rules group for this window */
824 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
825 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
826 g_object_unref (toolbar_rules_group);
827 g_object_unref (clipboard_rules_group);
829 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
831 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);
832 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
833 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
834 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
835 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
836 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
837 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
838 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
839 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
840 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
841 G_CALLBACK (modest_ui_actions_on_details), obj);
842 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
843 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
844 g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
845 G_CALLBACK (modest_ui_actions_on_limit_error), obj);
846 g_signal_connect (G_OBJECT(priv->msg_view), "handle_calendar",
847 G_CALLBACK (on_handle_calendar), obj);
848 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
849 G_CALLBACK (on_fetch_image), obj);
851 g_signal_connect (G_OBJECT (obj), "key-release-event",
852 G_CALLBACK (modest_msg_view_window_key_event),
855 g_signal_connect (G_OBJECT (obj), "key-press-event",
856 G_CALLBACK (modest_msg_view_window_key_event),
859 g_signal_connect (G_OBJECT (obj), "move-focus",
860 G_CALLBACK (on_move_focus), obj);
862 g_signal_connect (G_OBJECT (obj), "map-event",
863 G_CALLBACK (_modest_msg_view_window_map_event),
866 /* Mail Operation Queue */
867 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
869 G_CALLBACK (on_queue_changed),
872 /* Account manager */
873 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
875 G_CALLBACK(on_account_removed),
878 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
879 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
881 /* First add out toolbar ... */
882 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
884 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
886 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
887 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
888 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
889 G_CALLBACK (modest_msg_view_window_isearch_toolbar_close), obj);
890 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
891 G_CALLBACK (modest_msg_view_window_isearch_toolbar_search), obj);
892 priv->last_search = NULL;
894 /* Init the clipboard actions dim status */
895 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
897 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
902 /* FIXME: parameter checks */
904 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
905 const gchar *modest_account_name,
906 const gchar *mailbox,
907 const gchar *msg_uid,
909 GtkTreeRowReference *row_reference)
911 ModestMsgViewWindow *window = NULL;
912 ModestMsgViewWindowPrivate *priv = NULL;
913 TnyFolder *header_folder = NULL;
914 ModestHeaderView *header_view = NULL;
915 ModestWindowMgr *mgr = NULL;
918 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
921 mgr = modest_runtime_get_window_mgr ();
922 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
923 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
925 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
927 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
928 priv->top_msg = NULL;
930 /* Remember the message list's TreeModel so we can detect changes
931 * and change the list selection when necessary: */
932 header_folder = modest_header_view_get_folder (header_view);
934 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
935 TNY_FOLDER_TYPE_OUTBOX);
936 priv->header_folder_id = tny_folder_get_id (header_folder);
937 g_object_unref(header_folder);
940 /* Setup row references and connect signals */
941 priv->header_model = g_object_ref (model);
943 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
944 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
945 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
946 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
948 priv->row_reference = NULL;
949 priv->next_row_reference = NULL;
952 /* Connect signals */
953 priv->row_changed_handler =
954 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
955 G_CALLBACK(modest_msg_view_window_on_row_changed),
957 priv->row_deleted_handler =
958 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
959 G_CALLBACK(modest_msg_view_window_on_row_deleted),
961 priv->row_inserted_handler =
962 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
963 G_CALLBACK(modest_msg_view_window_on_row_inserted),
965 priv->rows_reordered_handler =
966 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
967 G_CALLBACK(modest_msg_view_window_on_row_reordered),
970 if (header_view != NULL){
971 modest_header_view_add_observer(header_view,
972 MODEST_HEADER_VIEW_OBSERVER(window));
975 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
976 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
977 update_branding (MODEST_MSG_VIEW_WINDOW (window));
979 /* gtk_widget_show_all (GTK_WIDGET (window)); */
980 modest_msg_view_window_update_priority (window);
981 /* Check dimming rules */
982 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
983 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
984 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
986 return MODEST_WINDOW(window);
990 modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
991 const gchar *mailbox,
992 const gchar *msg_uid)
994 ModestMsgViewWindow *window = NULL;
995 ModestMsgViewWindowPrivate *priv = NULL;
996 ModestWindowMgr *mgr = NULL;
998 TnyAccount *account = NULL;
1000 mgr = modest_runtime_get_window_mgr ();
1001 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1002 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1004 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1006 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1007 priv->top_msg = NULL;
1009 is_merge = g_str_has_prefix (msg_uid, "merge:");
1011 /* Get the account */
1013 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1016 if (is_merge || account) {
1017 TnyFolder *folder = NULL;
1019 /* Try to get the message, if it's already downloaded
1020 we don't need to connect */
1022 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
1024 ModestTnyAccountStore *account_store;
1025 ModestTnyLocalFoldersAccount *local_folders_account;
1027 account_store = modest_runtime_get_account_store ();
1028 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
1029 modest_tny_account_store_get_local_folders_account (account_store));
1030 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
1031 g_object_unref (local_folders_account);
1035 gboolean device_online;
1037 device = modest_runtime_get_device();
1038 device_online = tny_device_is_online (device);
1039 if (device_online) {
1040 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1042 TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
1044 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1045 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
1046 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1047 g_object_unref (msg);
1048 /* Sync flags to server */
1049 sync_flags (MODEST_MSG_VIEW_WINDOW (window));
1051 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1054 g_object_unref (folder);
1059 /* Check dimming rules */
1060 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1061 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1062 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1064 return MODEST_WINDOW(window);
1068 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1069 const gchar *modest_account_name,
1070 const gchar *mailbox,
1071 const gchar *msg_uid,
1072 GtkTreeRowReference *row_reference)
1074 ModestMsgViewWindow *window = NULL;
1075 ModestMsgViewWindowPrivate *priv = NULL;
1076 TnyFolder *header_folder = NULL;
1077 ModestWindowMgr *mgr = NULL;
1081 mgr = modest_runtime_get_window_mgr ();
1082 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1083 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1085 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1087 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1088 priv->top_msg = NULL;
1090 /* Remember the message list's TreeModel so we can detect changes
1091 * and change the list selection when necessary: */
1093 if (header_view != NULL){
1094 header_folder = modest_header_view_get_folder(header_view);
1095 /* This could happen if the header folder was
1096 unseleted before opening this msg window (for
1097 example if the user selects an account in the
1098 folder view of the main window */
1099 if (header_folder) {
1100 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1101 TNY_FOLDER_TYPE_OUTBOX);
1102 priv->header_folder_id = tny_folder_get_id(header_folder);
1103 g_object_unref(header_folder);
1107 /* Setup row references and connect signals */
1108 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1109 g_object_ref (priv->header_model);
1111 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
1112 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1113 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1114 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1116 priv->row_reference = NULL;
1117 priv->next_row_reference = NULL;
1120 /* Connect signals */
1121 priv->row_changed_handler =
1122 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1123 G_CALLBACK(modest_msg_view_window_on_row_changed),
1125 priv->row_deleted_handler =
1126 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1127 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1129 priv->row_inserted_handler =
1130 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1131 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1133 priv->rows_reordered_handler =
1134 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1135 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1138 if (header_view != NULL){
1139 modest_header_view_add_observer(header_view,
1140 MODEST_HEADER_VIEW_OBSERVER(window));
1143 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1144 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1146 if (priv->row_reference) {
1147 path = gtk_tree_row_reference_get_path (priv->row_reference);
1148 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1150 gtk_tree_model_get (priv->header_model, &iter,
1151 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1153 message_reader (window, priv, header, NULL, NULL, priv->row_reference);
1154 g_object_unref (header);
1156 gtk_tree_path_free (path);
1158 /* Check dimming rules */
1159 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1160 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1161 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1163 return MODEST_WINDOW(window);
1167 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1168 const gchar *modest_account_name,
1169 const gchar *mailbox,
1170 const gchar *msg_uid)
1172 ModestMsgViewWindow *window = NULL;
1173 ModestMsgViewWindowPrivate *priv = NULL;
1174 ModestWindowMgr *mgr = NULL;
1176 mgr = modest_runtime_get_window_mgr ();
1177 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1178 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1179 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1181 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1182 priv->top_msg = NULL;
1184 /* Remember that this is a search result,
1185 * so we can disable some UI appropriately: */
1186 priv->is_search_result = TRUE;
1188 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1189 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1191 update_window_title (window);
1192 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1193 modest_msg_view_window_update_priority (window);
1195 /* Check dimming rules */
1196 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1197 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1198 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1200 return MODEST_WINDOW(window);
1204 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1206 ModestMsgViewWindowPrivate *priv = NULL;
1208 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1209 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1211 return (priv->other_body != NULL);
1215 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1216 TnyMimePart *other_body,
1218 const gchar *modest_account_name,
1219 const gchar *mailbox,
1220 const gchar *msg_uid)
1222 GObject *obj = NULL;
1223 ModestMsgViewWindowPrivate *priv;
1224 ModestWindowMgr *mgr = NULL;
1226 g_return_val_if_fail (msg, NULL);
1227 mgr = modest_runtime_get_window_mgr ();
1228 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1229 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1230 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1231 modest_account_name, mailbox, msg_uid);
1234 priv->other_body = g_object_ref (other_body);
1235 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1237 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1240 priv->top_msg = g_object_ref (top_msg);
1242 priv->top_msg = NULL;
1244 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1245 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1247 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1249 /* Check dimming rules */
1250 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1251 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1252 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1254 return MODEST_WINDOW(obj);
1258 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1260 const gchar *modest_account_name,
1261 const gchar *mailbox,
1262 const gchar *msg_uid)
1264 return modest_msg_view_window_new_with_other_body (msg, NULL, top_msg, modest_account_name, mailbox, msg_uid);
1268 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1271 ModestMsgViewWindow *window)
1273 check_dimming_rules_after_change (window);
1277 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1279 ModestMsgViewWindow *window)
1281 check_dimming_rules_after_change (window);
1283 /* The window could have dissapeared */
1286 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1288 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1289 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1293 /* On insertions we check if the folder still has the message we are
1294 * showing or do not. If do not, we do nothing. Which means we are still
1295 * not attached to any header folder and thus next/prev buttons are
1296 * still dimmed. Once the message that is shown by msg-view is found, the
1297 * new model of header-view will be attached and the references will be set.
1298 * On each further insertions dimming rules will be checked. However
1299 * this requires extra CPU time at least works.
1300 * (An message might be deleted from TnyFolder and thus will not be
1301 * inserted into the model again for example if it is removed by the
1302 * imap server and the header view is refreshed.)
1305 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1306 GtkTreePath *tree_path,
1307 GtkTreeIter *tree_iter,
1308 ModestMsgViewWindow *window)
1310 ModestMsgViewWindowPrivate *priv = NULL;
1311 TnyHeader *header = NULL;
1313 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1314 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1316 g_assert (model == priv->header_model);
1318 /* Check if the newly inserted message is the same we are actually
1319 * showing. IF not, we should remain detached from the header model
1320 * and thus prev and next toolbar buttons should remain dimmed. */
1321 gtk_tree_model_get (model, tree_iter,
1322 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1325 if (TNY_IS_HEADER (header)) {
1328 uid = modest_tny_folder_get_header_unique_id (header);
1329 if (!g_str_equal(priv->msg_uid, uid)) {
1330 check_dimming_rules_after_change (window);
1332 g_object_unref (G_OBJECT(header));
1336 g_object_unref(G_OBJECT(header));
1339 if (priv->row_reference) {
1340 gtk_tree_row_reference_free (priv->row_reference);
1343 /* Setup row_reference for the actual msg. */
1344 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1345 if (priv->row_reference == NULL) {
1346 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1350 /* Now set up next_row_reference. */
1351 if (priv->next_row_reference) {
1352 gtk_tree_row_reference_free (priv->next_row_reference);
1355 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1356 select_next_valid_row (priv->header_model,
1357 &(priv->next_row_reference), FALSE, priv->is_outbox);
1359 /* Connect the remaining callbacks to become able to detect
1360 * changes in header-view. */
1361 priv->row_changed_handler =
1362 g_signal_connect (priv->header_model, "row-changed",
1363 G_CALLBACK (modest_msg_view_window_on_row_changed),
1365 priv->row_deleted_handler =
1366 g_signal_connect (priv->header_model, "row-deleted",
1367 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1369 priv->rows_reordered_handler =
1370 g_signal_connect (priv->header_model, "rows-reordered",
1371 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1374 check_dimming_rules_after_change (window);
1378 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1382 ModestMsgViewWindow *window)
1384 ModestMsgViewWindowPrivate *priv = NULL;
1385 gboolean already_changed = FALSE;
1387 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1389 /* If the current row was reordered select the proper next
1390 valid row. The same if the next row reference changes */
1391 if (!priv->row_reference ||
1392 !gtk_tree_row_reference_valid (priv->row_reference))
1395 if (priv->next_row_reference &&
1396 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1397 GtkTreePath *cur, *next;
1398 /* Check that the order is still the correct one */
1399 cur = gtk_tree_row_reference_get_path (priv->row_reference);
1400 next = gtk_tree_row_reference_get_path (priv->next_row_reference);
1401 gtk_tree_path_next (cur);
1402 if (gtk_tree_path_compare (cur, next) != 0) {
1403 gtk_tree_row_reference_free (priv->next_row_reference);
1404 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1405 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1406 already_changed = TRUE;
1408 gtk_tree_path_free (cur);
1409 gtk_tree_path_free (next);
1411 if (priv->next_row_reference)
1412 gtk_tree_row_reference_free (priv->next_row_reference);
1413 /* Update next row reference */
1414 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1415 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1416 already_changed = TRUE;
1419 check_dimming_rules_after_change (window);
1422 /* The modest_msg_view_window_update_model_replaced implements update
1423 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1424 * actually belongs to the header-view is the same as the TnyFolder of
1425 * the message of msg-view or not. If they are different, there is
1426 * nothing to do. If they are the same, then the model has replaced and
1427 * the reference in msg-view shall be replaced from the old model to
1428 * the new model. In this case the view will be detached from it's
1429 * header folder. From this point the next/prev buttons are dimmed.
1432 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1433 GtkTreeModel *model,
1434 const gchar *tny_folder_id)
1436 ModestMsgViewWindowPrivate *priv = NULL;
1437 ModestMsgViewWindow *window = NULL;
1439 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1440 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1442 window = MODEST_MSG_VIEW_WINDOW(observer);
1443 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1445 /* If there is an other folder in the header-view then we do
1446 * not care about it's model (msg list). Else if the
1447 * header-view shows the folder the msg shown by us is in, we
1448 * shall replace our model reference and make some check. */
1449 if(model == NULL || tny_folder_id == NULL ||
1450 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1453 /* Model is changed(replaced), so we should forget the old
1454 * one. Because there might be other references and there
1455 * might be some change on the model even if we unreferenced
1456 * it, we need to disconnect our signals here. */
1457 if (priv->header_model) {
1458 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1459 priv->row_changed_handler))
1460 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1461 priv->row_changed_handler);
1462 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1463 priv->row_deleted_handler))
1464 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1465 priv->row_deleted_handler);
1466 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1467 priv->row_inserted_handler))
1468 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1469 priv->row_inserted_handler);
1470 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1471 priv->rows_reordered_handler))
1472 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1473 priv->rows_reordered_handler);
1476 if (priv->row_reference)
1477 gtk_tree_row_reference_free (priv->row_reference);
1478 if (priv->next_row_reference)
1479 gtk_tree_row_reference_free (priv->next_row_reference);
1480 g_object_unref(priv->header_model);
1483 priv->row_changed_handler = 0;
1484 priv->row_deleted_handler = 0;
1485 priv->row_inserted_handler = 0;
1486 priv->rows_reordered_handler = 0;
1487 priv->next_row_reference = NULL;
1488 priv->row_reference = NULL;
1489 priv->header_model = NULL;
1492 priv->header_model = g_object_ref (model);
1494 /* Also we must connect to the new model for row insertions.
1495 * Only for insertions now. We will need other ones only after
1496 * the msg is show by msg-view is added to the new model. */
1497 priv->row_inserted_handler =
1498 g_signal_connect (priv->header_model, "row-inserted",
1499 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1502 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1503 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1507 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1509 ModestMsgViewWindowPrivate *priv= NULL;
1511 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1512 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1514 return priv->progress_hint;
1518 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1520 ModestMsgViewWindowPrivate *priv= NULL;
1522 TnyHeader *header = NULL;
1523 GtkTreePath *path = NULL;
1526 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1527 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1529 /* If the message was not obtained from a treemodel,
1530 * for instance if it was opened directly by the search UI:
1532 if (priv->header_model == NULL ||
1533 priv->row_reference == NULL ||
1534 !gtk_tree_row_reference_valid (priv->row_reference)) {
1535 msg = modest_msg_view_window_get_message (self);
1537 header = tny_msg_get_header (msg);
1538 g_object_unref (msg);
1543 /* Get iter of the currently selected message in the header view: */
1544 path = gtk_tree_row_reference_get_path (priv->row_reference);
1545 g_return_val_if_fail (path != NULL, NULL);
1546 gtk_tree_model_get_iter (priv->header_model,
1550 /* Get current message header */
1551 gtk_tree_model_get (priv->header_model, &iter,
1552 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1555 gtk_tree_path_free (path);
1560 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1562 ModestMsgViewWindowPrivate *priv;
1564 g_return_val_if_fail (self, NULL);
1566 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1568 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1572 modest_msg_view_window_get_top_message (ModestMsgViewWindow *self)
1574 ModestMsgViewWindowPrivate *priv;
1576 g_return_val_if_fail (self, NULL);
1578 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1581 return g_object_ref (priv->top_msg);
1587 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1589 ModestMsgViewWindowPrivate *priv;
1591 g_return_val_if_fail (self, NULL);
1593 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1595 return (const gchar*) priv->msg_uid;
1598 /* Used for the Ctrl+F accelerator */
1600 modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
1603 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1604 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1606 if (GTK_WIDGET_VISIBLE (priv->isearch_toolbar)) {
1607 modest_msg_view_window_isearch_toolbar_close (obj, data);
1609 modest_msg_view_window_show_isearch_toolbar (obj, data);
1613 /* Handler for menu option */
1615 modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj,
1618 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1619 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1621 gtk_widget_show (priv->isearch_toolbar);
1622 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1625 /* Handler for click on the "X" close button in isearch toolbar */
1627 modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
1628 ModestMsgViewWindow *obj)
1630 ModestMsgViewWindowPrivate *priv;
1632 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1635 gtk_widget_hide (priv->isearch_toolbar);
1636 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1640 modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
1641 ModestMsgViewWindow *obj)
1643 const gchar *current_search;
1644 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1646 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1647 modest_platform_system_banner (NULL, NULL, _("mail_ib_nothing_to_find"));
1651 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
1653 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1654 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
1658 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1660 g_free (priv->last_search);
1661 priv->last_search = g_strdup (current_search);
1662 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1665 modest_platform_system_banner (NULL, NULL,
1666 _HL_IB_FIND_NO_MATCHES);
1667 g_free (priv->last_search);
1668 priv->last_search = NULL;
1670 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1673 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1674 modest_platform_system_banner (NULL, NULL,
1675 _HL_IB_FIND_COMPLETE);
1676 g_free (priv->last_search);
1677 priv->last_search = NULL;
1679 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1686 modest_msg_view_window_set_zoom (ModestWindow *window,
1689 ModestMsgViewWindowPrivate *priv;
1690 ModestWindowPrivate *parent_priv;
1692 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1694 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1695 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1696 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1701 modest_msg_view_window_get_zoom (ModestWindow *window)
1703 ModestMsgViewWindowPrivate *priv;
1705 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1707 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1708 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1712 modest_msg_view_window_zoom_plus (ModestWindow *window)
1715 ModestMsgViewWindowPrivate *priv;
1719 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1720 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1722 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1724 if (zoom_level >= 2.0) {
1725 modest_platform_system_banner (NULL, NULL,
1726 _CS_MAX_ZOOM_LEVEL_REACHED);
1728 } else if (zoom_level >= 1.5) {
1730 } else if (zoom_level >= 1.2) {
1732 } else if (zoom_level >= 1.0) {
1734 } else if (zoom_level >= 0.8) {
1736 } else if (zoom_level >= 0.5) {
1742 /* set zoom level */
1743 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1744 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1745 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1746 g_free (banner_text);
1747 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1753 modest_msg_view_window_zoom_minus (ModestWindow *window)
1756 ModestMsgViewWindowPrivate *priv;
1760 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1761 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1763 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1765 if (zoom_level <= 0.5) {
1766 modest_platform_system_banner (NULL, NULL,
1767 _CS_MIN_ZOOM_LEVEL_REACHED);
1769 } else if (zoom_level <= 0.8) {
1771 } else if (zoom_level <= 1.0) {
1773 } else if (zoom_level <= 1.2) {
1775 } else if (zoom_level <= 1.5) {
1777 } else if (zoom_level <= 2.0) {
1783 /* set zoom level */
1784 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1785 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1786 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1787 g_free (banner_text);
1788 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1794 modest_msg_view_window_key_event (GtkWidget *window,
1800 focus = gtk_container_get_focus_child ((GtkContainer *) window);
1802 /* for the isearch toolbar case */
1803 if (focus && GTK_IS_ENTRY (focus)) {
1804 if (event->keyval == GDK_BackSpace) {
1806 copy = gdk_event_copy ((GdkEvent *) event);
1807 gtk_widget_event (focus, copy);
1808 gdk_event_free (copy);
1818 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1821 ModestMsgViewWindowPrivate *priv;
1822 GtkTreeIter tmp_iter;
1823 gboolean is_last_selected;
1825 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1826 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1828 /*if no model (so no rows at all), then virtually we are the last*/
1829 if (!priv->header_model || !priv->row_reference)
1832 if (!gtk_tree_row_reference_valid (priv->row_reference))
1835 path = gtk_tree_row_reference_get_path (priv->row_reference);
1839 is_last_selected = TRUE;
1840 while (is_last_selected) {
1842 gtk_tree_path_next (path);
1843 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1845 gtk_tree_model_get (priv->header_model, &tmp_iter,
1846 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1849 if (msg_is_visible (header, priv->is_outbox))
1850 is_last_selected = FALSE;
1851 g_object_unref(G_OBJECT(header));
1854 gtk_tree_path_free (path);
1855 return is_last_selected;
1859 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1861 ModestMsgViewWindowPrivate *priv;
1863 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1864 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1866 return priv->header_model != NULL;
1870 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1872 ModestMsgViewWindowPrivate *priv;
1874 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1875 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1877 return priv->is_search_result;
1881 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1883 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1885 if (!check_outbox) {
1888 ModestTnySendQueueStatus status;
1889 status = modest_tny_all_send_queues_get_msg_status (header);
1890 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1891 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1896 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1899 ModestMsgViewWindowPrivate *priv;
1900 gboolean is_first_selected;
1901 GtkTreeIter tmp_iter;
1903 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1904 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1906 /*if no model (so no rows at all), then virtually we are the first*/
1907 if (!priv->header_model || !priv->row_reference)
1910 if (!gtk_tree_row_reference_valid (priv->row_reference))
1913 path = gtk_tree_row_reference_get_path (priv->row_reference);
1917 is_first_selected = TRUE;
1918 while (is_first_selected) {
1920 if(!gtk_tree_path_prev (path))
1922 /* Here the 'if' is needless for logic, but let make sure
1923 * iter is valid for gtk_tree_model_get. */
1924 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1926 gtk_tree_model_get (priv->header_model, &tmp_iter,
1927 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1930 if (msg_is_visible (header, priv->is_outbox))
1931 is_first_selected = FALSE;
1932 g_object_unref(G_OBJECT(header));
1935 gtk_tree_path_free (path);
1936 return is_first_selected;
1943 GtkTreeRowReference *row_reference;
1947 message_reader_performer (gboolean canceled,
1949 ModestWindow *parent_window,
1950 TnyAccount *account,
1953 ModestMailOperation *mail_op = NULL;
1954 MsgReaderInfo *info;
1956 info = (MsgReaderInfo *) user_data;
1957 if (canceled || err) {
1958 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1959 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (parent_window));
1963 /* Register the header - it'll be unregistered in the callback */
1965 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1967 /* New mail operation */
1968 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1969 modest_ui_actions_disk_operations_error_handler,
1972 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1974 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1976 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1977 g_object_unref (mail_op);
1979 /* Update dimming rules */
1980 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1981 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1984 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1985 g_free (info->msg_uid);
1987 g_object_unref (info->folder);
1989 g_object_unref (info->header);
1990 g_slice_free (MsgReaderInfo, info);
1995 * Reads the message whose summary item is @header. It takes care of
1996 * several things, among others:
1998 * If the message was not previously downloaded then ask the user
1999 * before downloading. If there is no connection launch the connection
2000 * dialog. Update toolbar dimming rules.
2002 * Returns: TRUE if the mail operation was started, otherwise if the
2003 * user do not want to download the message, or if the user do not
2004 * want to connect, then the operation is not issued
2007 message_reader (ModestMsgViewWindow *window,
2008 ModestMsgViewWindowPrivate *priv,
2010 const gchar *msg_uid,
2012 GtkTreeRowReference *row_reference)
2014 ModestWindowMgr *mgr;
2015 TnyAccount *account = NULL;
2016 MsgReaderInfo *info;
2018 /* We set the header from model while we're loading */
2019 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
2020 modest_window_set_title (MODEST_WINDOW (window), _CS_UPDATING);
2026 g_object_ref (folder);
2028 mgr = modest_runtime_get_window_mgr ();
2029 /* Msg download completed */
2030 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
2032 /* Ask the user if he wants to download the message if
2034 if (!tny_device_is_online (modest_runtime_get_device())) {
2035 GtkResponseType response;
2036 GtkWindow *toplevel;
2038 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
2039 response = modest_platform_run_confirmation_dialog (toplevel, _("mcen_nc_get_msg"));
2040 if (response == GTK_RESPONSE_CANCEL) {
2041 update_window_title (window);
2046 folder = tny_header_get_folder (header);
2048 info = g_slice_new (MsgReaderInfo);
2049 info->msg_uid = g_strdup (msg_uid);
2051 info->header = g_object_ref (header);
2053 info->header = NULL;
2055 info->folder = g_object_ref (folder);
2057 info->folder = NULL;
2058 if (row_reference) {
2059 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2061 info->row_reference = NULL;
2064 /* Offer the connection dialog if necessary */
2065 modest_platform_connect_if_remote_and_perform ((ModestWindow *) window,
2067 TNY_FOLDER_STORE (folder),
2068 message_reader_performer,
2071 g_object_unref (folder);
2077 folder = tny_header_get_folder (header);
2080 account = tny_folder_get_account (folder);
2082 info = g_slice_new (MsgReaderInfo);
2083 info->msg_uid = g_strdup (msg_uid);
2085 info->folder = g_object_ref (folder);
2087 info->folder = NULL;
2089 info->header = g_object_ref (header);
2091 info->header = NULL;
2093 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2095 info->row_reference = NULL;
2097 message_reader_performer (FALSE, NULL, (ModestWindow *) window, account, info);
2099 g_object_unref (account);
2101 g_object_unref (folder);
2107 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2109 ModestMsgViewWindowPrivate *priv;
2110 GtkTreePath *path= NULL;
2111 GtkTreeIter tmp_iter;
2113 gboolean retval = TRUE;
2114 GtkTreeRowReference *row_reference = NULL;
2116 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2117 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2119 if (!priv->row_reference)
2122 /* Update the next row reference if it's not valid. This could
2123 happen if for example the header which it was pointing to,
2124 was deleted. The best place to do it is in the row-deleted
2125 handler but the tinymail model do not work like the glib
2126 tree models and reports the deletion when the row is still
2128 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2129 if (priv->next_row_reference) {
2130 gtk_tree_row_reference_free (priv->next_row_reference);
2132 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2133 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2134 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2136 priv->next_row_reference = NULL;
2139 if (priv->next_row_reference)
2140 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2144 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2146 gtk_tree_model_get_iter (priv->header_model,
2149 gtk_tree_path_free (path);
2151 gtk_tree_model_get (priv->header_model, &tmp_iter,
2152 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2155 /* Read the message & show it */
2156 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2159 gtk_tree_row_reference_free (row_reference);
2162 g_object_unref (header);
2168 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2170 ModestMsgViewWindowPrivate *priv = NULL;
2172 gboolean finished = FALSE;
2173 gboolean retval = FALSE;
2175 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2176 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2178 if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
2179 gtk_tree_row_reference_free (priv->row_reference);
2180 priv->row_reference = NULL;
2183 /* Return inmediatly if there is no header model */
2184 if (!priv->header_model || !priv->row_reference)
2187 path = gtk_tree_row_reference_get_path (priv->row_reference);
2188 while (!finished && gtk_tree_path_prev (path)) {
2192 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2193 gtk_tree_model_get (priv->header_model, &iter,
2194 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2198 if (msg_is_visible (header, priv->is_outbox)) {
2199 GtkTreeRowReference *row_reference;
2200 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2201 /* Read the message & show it */
2202 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2203 gtk_tree_row_reference_free (row_reference);
2207 g_object_unref (header);
2211 gtk_tree_path_free (path);
2216 view_msg_cb (ModestMailOperation *mail_op,
2223 ModestMsgViewWindow *self = NULL;
2224 ModestMsgViewWindowPrivate *priv = NULL;
2225 GtkTreeRowReference *row_reference = NULL;
2227 /* Unregister the header (it was registered before creating the mail operation) */
2228 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2230 row_reference = (GtkTreeRowReference *) user_data;
2233 gtk_tree_row_reference_free (row_reference);
2234 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2236 /* Restore window title */
2237 update_window_title (self);
2238 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2239 g_object_unref (self);
2244 /* If there was any error */
2245 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2247 gtk_tree_row_reference_free (row_reference);
2248 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2250 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2251 /* First we check if the parent is a folder window */
2252 if (priv->msg_uid && !modest_window_mgr_get_folder_window (MODEST_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2254 TnyAccount *account = NULL;
2255 GtkWidget *header_window = NULL;
2257 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2259 /* Get the account */
2261 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2264 if (is_merge || account) {
2265 TnyFolder *folder = NULL;
2267 /* Try to get the message, if it's already downloaded
2268 we don't need to connect */
2270 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2273 ModestTnyAccountStore *account_store;
2274 ModestTnyLocalFoldersAccount *local_folders_account;
2276 account_store = modest_runtime_get_account_store ();
2277 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2278 modest_tny_account_store_get_local_folders_account (account_store));
2279 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2280 g_object_unref (local_folders_account);
2282 if (account) g_object_unref (account);
2285 header_window = (GtkWidget *)
2286 modest_header_window_new (
2288 modest_window_get_active_account (MODEST_WINDOW (self)),
2289 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2290 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2291 MODEST_WINDOW (header_window),
2293 gtk_widget_destroy (GTK_WIDGET (header_window));
2295 gtk_widget_show_all (GTK_WIDGET (header_window));
2297 g_object_unref (folder);
2303 /* Restore window title */
2304 update_window_title (self);
2305 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2306 g_object_unref (self);
2311 /* Get the window */
2312 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2313 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2314 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2316 /* Update the row reference */
2317 if (priv->row_reference != NULL) {
2318 gtk_tree_row_reference_free (priv->row_reference);
2319 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2320 if (priv->next_row_reference != NULL) {
2321 gtk_tree_row_reference_free (priv->next_row_reference);
2323 if (priv->row_reference) {
2324 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2325 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2327 priv->next_row_reference = NULL;
2331 /* Mark header as read */
2332 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN)) {
2335 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2336 uid = modest_tny_folder_get_header_unique_id (header);
2337 modest_platform_emit_msg_read_changed_signal (uid, TRUE);
2341 /* Set new message */
2342 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2343 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2344 modest_msg_view_window_update_priority (self);
2345 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2346 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2347 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2350 /* Set the new message uid of the window */
2351 if (priv->msg_uid) {
2352 g_free (priv->msg_uid);
2353 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2356 /* Notify the observers */
2357 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2358 0, priv->header_model, priv->row_reference);
2360 /* Sync the flags if the message is not opened from a header
2361 model, i.e, if it's opened from a notification */
2362 if (!priv->header_model)
2366 g_object_unref (self);
2368 gtk_tree_row_reference_free (row_reference);
2372 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2374 ModestMsgViewWindowPrivate *priv;
2376 TnyFolderType folder_type;
2378 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2380 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2382 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2386 folder = tny_msg_get_folder (msg);
2388 folder_type = modest_tny_folder_guess_folder_type (folder);
2389 g_object_unref (folder);
2391 g_object_unref (msg);
2399 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2401 ModestMsgViewWindowPrivate *priv;
2402 TnyHeader *header = NULL;
2403 TnyHeaderFlags flags = 0;
2405 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2407 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2409 GtkTreePath *path = NULL;
2411 path = gtk_tree_row_reference_get_path (priv->row_reference);
2412 g_return_if_fail (path != NULL);
2413 gtk_tree_model_get_iter (priv->header_model,
2415 gtk_tree_row_reference_get_path (priv->row_reference));
2417 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2419 gtk_tree_path_free (path);
2422 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2424 header = tny_msg_get_header (msg);
2425 g_object_unref (msg);
2430 flags = tny_header_get_flags (header);
2431 g_object_unref(G_OBJECT(header));
2434 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2439 toolbar_resize (ModestMsgViewWindow *self)
2441 ModestMsgViewWindowPrivate *priv = NULL;
2442 ModestWindowPrivate *parent_priv = NULL;
2444 gint static_button_size;
2445 ModestWindowMgr *mgr;
2447 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2448 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2449 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2451 mgr = modest_runtime_get_window_mgr ();
2452 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2454 if (parent_priv->toolbar) {
2455 /* Set expandable and homogeneous tool buttons */
2456 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2457 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2458 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2459 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2460 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2461 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2462 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2463 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2464 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2465 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2466 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2467 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2468 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2469 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2470 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2471 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2473 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2474 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2479 modest_msg_view_window_show_toolbar (ModestWindow *self,
2480 gboolean show_toolbar)
2482 ModestMsgViewWindowPrivate *priv = NULL;
2483 ModestWindowPrivate *parent_priv;
2485 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2486 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2488 /* Set optimized view status */
2489 priv->optimized_view = !show_toolbar;
2491 if (!parent_priv->toolbar) {
2492 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2495 #ifdef MODEST_TOOLKIT_HILDON2
2496 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2498 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), GTK_ICON_SIZE_LARGE_TOOLBAR);
2500 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2502 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2503 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2504 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2506 modest_window_add_toolbar (MODEST_WINDOW (self),
2507 GTK_TOOLBAR (parent_priv->toolbar));
2512 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2513 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2514 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2516 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2517 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2518 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2520 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2523 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2524 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2529 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2531 ModestMsgViewWindow *window)
2533 if (!GTK_WIDGET_VISIBLE (window))
2536 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2540 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2542 ModestMsgViewWindowPrivate *priv;
2544 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2545 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2547 return priv->progress_hint;
2551 observers_empty (ModestMsgViewWindow *self)
2554 ModestMsgViewWindowPrivate *priv;
2555 gboolean is_empty = TRUE;
2556 guint pending_ops = 0;
2558 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2559 tmp = priv->progress_widgets;
2561 /* Check all observers */
2562 while (tmp && is_empty) {
2563 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2564 is_empty = pending_ops == 0;
2566 tmp = g_slist_next(tmp);
2573 on_account_removed (TnyAccountStore *account_store,
2574 TnyAccount *account,
2577 /* Do nothing if it's a transport account, because we only
2578 show the messages of a store account */
2579 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2580 const gchar *parent_acc = NULL;
2581 const gchar *our_acc = NULL;
2583 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2584 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2586 /* Close this window if I'm showing a message of the removed account */
2587 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2588 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2593 on_mail_operation_started (ModestMailOperation *mail_op,
2596 ModestMsgViewWindow *self;
2597 ModestMailOperationTypeOperation op_type;
2599 ModestMsgViewWindowPrivate *priv;
2600 GObject *source = NULL;
2602 self = MODEST_MSG_VIEW_WINDOW (user_data);
2603 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2604 op_type = modest_mail_operation_get_type_operation (mail_op);
2605 tmp = priv->progress_widgets;
2606 source = modest_mail_operation_get_source(mail_op);
2607 if (G_OBJECT (self) == source) {
2608 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2609 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2610 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2611 set_progress_hint (self, TRUE);
2613 modest_progress_object_add_operation (
2614 MODEST_PROGRESS_OBJECT (tmp->data),
2616 tmp = g_slist_next (tmp);
2620 g_object_unref (source);
2622 /* Update dimming rules */
2623 check_dimming_rules_after_change (self);
2627 on_mail_operation_finished (ModestMailOperation *mail_op,
2630 ModestMsgViewWindow *self;
2631 ModestMailOperationTypeOperation op_type;
2633 ModestMsgViewWindowPrivate *priv;
2635 self = MODEST_MSG_VIEW_WINDOW (user_data);
2636 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2637 op_type = modest_mail_operation_get_type_operation (mail_op);
2638 tmp = priv->progress_widgets;
2640 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2641 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2642 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2644 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2646 tmp = g_slist_next (tmp);
2649 /* If no more operations are being observed, NORMAL mode is enabled again */
2650 if (observers_empty (self)) {
2651 set_progress_hint (self, FALSE);
2655 /* Update dimming rules. We have to do this right here
2656 and not in view_msg_cb because at that point the
2657 transfer mode is still enabled so the dimming rule
2658 won't let the user delete the message that has been
2659 readed for example */
2660 check_dimming_rules_after_change (self);
2664 on_queue_changed (ModestMailOperationQueue *queue,
2665 ModestMailOperation *mail_op,
2666 ModestMailOperationQueueNotification type,
2667 ModestMsgViewWindow *self)
2669 ModestMsgViewWindowPrivate *priv;
2671 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2673 /* If this operations was created by another window, do nothing */
2674 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2677 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2678 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2680 "operation-started",
2681 G_CALLBACK (on_mail_operation_started),
2683 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2685 "operation-finished",
2686 G_CALLBACK (on_mail_operation_finished),
2688 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2689 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2691 "operation-started");
2692 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2694 "operation-finished");
2699 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2701 ModestMsgViewWindowPrivate *priv;
2702 TnyList *selected_attachments = NULL;
2704 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2705 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2707 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2708 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2710 return selected_attachments;
2714 ModestMsgViewWindow *self;
2716 gchar *attachment_uid;
2717 } DecodeAsyncHelper;
2720 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2726 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2727 const gchar *content_type;
2728 ModestMsgViewWindowPrivate *priv;
2730 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2732 if (cancelled || err) {
2735 if ((err->domain == TNY_ERROR_DOMAIN) &&
2736 (err->code == TNY_IO_ERROR_WRITE) &&
2737 (errno == ENOSPC)) {
2738 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2740 msg = g_strdup (_("mail_ib_file_operation_failed"));
2742 modest_platform_information_banner (NULL, NULL, msg);
2748 /* It could happen that the window was closed. So we
2749 assume it is a cancelation */
2750 if (!GTK_WIDGET_VISIBLE (helper->self))
2753 /* Remove the progress hint */
2754 set_progress_hint (helper->self, FALSE);
2756 content_type = tny_mime_part_get_content_type (mime_part);
2757 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2758 ModestWindowMgr *mgr;
2759 ModestWindow *msg_win = NULL;
2762 const gchar *mailbox;
2763 TnyStream *file_stream;
2766 fd = g_open (helper->file_path, O_RDONLY, 0644);
2769 file_stream = tny_fs_stream_new (fd);
2771 mgr = modest_runtime_get_window_mgr ();
2773 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2774 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2777 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2779 msg = tny_camel_msg_new ();
2780 tny_camel_msg_parse (msg, file_stream);
2783 top_msg = g_object_ref (priv->top_msg);
2785 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2787 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2788 account, mailbox, helper->attachment_uid);
2789 if (top_msg) g_object_unref (top_msg);
2790 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2791 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2792 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2793 gtk_widget_show_all (GTK_WIDGET (msg_win));
2795 gtk_widget_destroy (GTK_WIDGET (msg_win));
2796 g_object_unref (msg);
2797 g_object_unref (file_stream);
2799 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2804 /* make the file read-only */
2805 g_chmod(helper->file_path, 0444);
2807 /* Activate the file */
2808 modest_platform_activate_file (helper->file_path, content_type);
2813 g_object_unref (helper->self);
2814 g_free (helper->file_path);
2815 g_free (helper->attachment_uid);
2816 g_slice_free (DecodeAsyncHelper, helper);
2820 view_attachment_connect_handler (gboolean canceled,
2822 GtkWindow *parent_window,
2823 TnyAccount *account,
2827 if (canceled || err) {
2828 g_object_unref (part);
2832 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2834 g_object_unref (part);
2838 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2839 TnyMimePart *mime_part)
2841 ModestMsgViewWindowPrivate *priv;
2842 const gchar *msg_uid;
2843 gchar *attachment_uid = NULL;
2844 gint attachment_index = 0;
2845 TnyList *attachments;
2847 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2848 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2849 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2851 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2852 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2853 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2854 g_object_unref (attachments);
2856 if (msg_uid && attachment_index >= 0) {
2857 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2860 if (mime_part == NULL) {
2861 gboolean error = FALSE;
2862 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2863 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2865 } else if (tny_list_get_length (selected_attachments) > 1) {
2866 modest_platform_system_banner (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2870 iter = tny_list_create_iterator (selected_attachments);
2871 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2872 g_object_unref (iter);
2874 if (selected_attachments)
2875 g_object_unref (selected_attachments);
2880 g_object_ref (mime_part);
2883 if (tny_mime_part_is_purged (mime_part))
2886 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2887 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2889 TnyAccount *account;
2891 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2893 /* Get the account */
2895 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2898 if (!tny_device_is_online (modest_runtime_get_device())) {
2899 modest_platform_connect_and_perform ((ModestWindow *) window,
2901 TNY_ACCOUNT (account),
2902 (ModestConnectedPerformer) view_attachment_connect_handler,
2903 g_object_ref (mime_part));
2908 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2909 gchar *filepath = NULL;
2910 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2911 gboolean show_error_banner = FALSE;
2912 TnyFsStream *temp_stream = NULL;
2913 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2916 if (temp_stream != NULL) {
2917 ModestAccountMgr *mgr;
2918 DecodeAsyncHelper *helper;
2919 gboolean decode_in_provider;
2920 ModestProtocol *protocol;
2921 const gchar *account;
2923 /* Activate progress hint */
2924 set_progress_hint (window, TRUE);
2926 helper = g_slice_new0 (DecodeAsyncHelper);
2927 helper->self = g_object_ref (window);
2928 helper->file_path = g_strdup (filepath);
2929 helper->attachment_uid = g_strdup (attachment_uid);
2931 decode_in_provider = FALSE;
2932 mgr = modest_runtime_get_account_mgr ();
2933 account = modest_window_get_active_account (MODEST_WINDOW (window));
2934 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2935 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2937 uri = g_strconcat ("file://", filepath, NULL);
2938 decode_in_provider =
2939 modest_account_protocol_decode_part_to_stream_async (
2940 MODEST_ACCOUNT_PROTOCOL (protocol),
2943 TNY_STREAM (temp_stream),
2944 on_decode_to_stream_async_handler,
2951 if (!decode_in_provider)
2952 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2953 on_decode_to_stream_async_handler,
2956 g_object_unref (temp_stream);
2957 /* NOTE: files in the temporary area will be automatically
2958 * cleaned after some time if they are no longer in use */
2961 const gchar *content_type;
2962 /* the file may already exist but it isn't writable,
2963 * let's try to open it anyway */
2964 content_type = tny_mime_part_get_content_type (mime_part);
2965 modest_platform_activate_file (filepath, content_type);
2967 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2968 show_error_banner = TRUE;
2973 if (show_error_banner)
2974 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2975 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2976 ModestWindowMgr *mgr;
2977 ModestWindow *msg_win = NULL;
2978 TnyMsg *current_msg;
2982 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2983 mgr = modest_runtime_get_window_mgr ();
2984 header = tny_msg_get_header (TNY_MSG (current_msg));
2985 found = modest_window_mgr_find_registered_message_uid (mgr,
2990 g_debug ("window for this body is already being created");
2994 /* it's not found, so create a new window for it */
2995 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2996 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2997 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2999 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3002 top_msg = g_object_ref (priv->top_msg);
3004 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3006 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
3007 account, mailbox, attachment_uid);
3009 if (top_msg) g_object_unref (top_msg);
3011 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3012 modest_window_get_zoom (MODEST_WINDOW (window)));
3013 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3014 gtk_widget_show_all (GTK_WIDGET (msg_win));
3016 gtk_widget_destroy (GTK_WIDGET (msg_win));
3018 g_object_unref (current_msg);
3020 /* message attachment */
3021 TnyHeader *header = NULL;
3022 ModestWindowMgr *mgr;
3023 ModestWindow *msg_win = NULL;
3026 header = tny_msg_get_header (TNY_MSG (mime_part));
3027 mgr = modest_runtime_get_window_mgr ();
3028 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3031 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3032 * thus, we don't do anything */
3033 g_debug ("window for is already being created");
3036 /* it's not found, so create a new window for it */
3037 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3038 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3039 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3041 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3043 top_msg = g_object_ref (priv->top_msg);
3045 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3046 msg_win = modest_msg_view_window_new_for_attachment (
3047 TNY_MSG (mime_part), top_msg, account,
3048 mailbox, attachment_uid);
3049 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3050 modest_window_get_zoom (MODEST_WINDOW (window)));
3051 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3052 gtk_widget_show_all (GTK_WIDGET (msg_win));
3054 gtk_widget_destroy (GTK_WIDGET (msg_win));
3060 g_free (attachment_uid);
3062 g_object_unref (mime_part);
3074 GnomeVFSResult result;
3076 ModestMsgViewWindow *window;
3079 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3080 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3081 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3082 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3085 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3089 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3090 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3091 g_free (pair->filename);
3092 g_object_unref (pair->part);
3093 g_slice_free (SaveMimePartPair, pair);
3095 g_list_free (info->pairs);
3098 g_object_unref (info->window);
3099 info->window = NULL;
3101 g_slice_free (SaveMimePartInfo, info);
3106 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3108 /* This is a GDK lock because we are an idle callback and
3109 * modest_platform_system_banner is or does Gtk+ code */
3111 gdk_threads_enter (); /* CHECKED */
3112 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3114 } else if (info->result == GNOME_VFS_OK) {
3115 modest_platform_system_banner (NULL, NULL, _CS_SAVED);
3116 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3119 /* Check if the uri belongs to the external mmc */
3120 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3121 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3123 msg = g_strdup (_KR("cerm_memory_card_full"));
3124 modest_platform_information_banner (NULL, NULL, msg);
3127 modest_platform_system_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
3129 set_progress_hint (info->window, FALSE);
3130 save_mime_part_info_free (info, FALSE);
3131 gdk_threads_leave (); /* CHECKED */
3137 save_mime_part_to_file_connect_handler (gboolean canceled,
3139 GtkWindow *parent_window,
3140 TnyAccount *account,
3141 SaveMimePartInfo *info)
3143 if (canceled || err) {
3144 if (canceled && !err) {
3145 info->result = GNOME_VFS_ERROR_CANCELLED;
3147 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3149 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3154 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3157 TnyAccount *account;
3158 ModestMsgViewWindowPrivate *priv;
3160 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3162 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3165 /* Get the account */
3167 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3170 modest_platform_connect_and_perform ((ModestWindow *) info->window,
3172 TNY_ACCOUNT (account),
3173 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3177 g_object_unref (account);
3183 save_mime_part_to_file (SaveMimePartInfo *info)
3185 GnomeVFSHandle *handle;
3187 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3189 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3190 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3191 gboolean check_online = TRUE;
3192 ModestMsgViewWindowPrivate *priv = NULL;
3194 /* Check if we really need to connect to save the mime part */
3195 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3196 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3197 check_online = FALSE;
3199 TnyAccountStore *acc_store;
3200 TnyAccount *account = NULL;
3202 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3203 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3206 if (tny_account_get_connection_status (account) ==
3207 TNY_CONNECTION_STATUS_CONNECTED)
3208 check_online = FALSE;
3209 g_object_unref (account);
3211 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3216 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3221 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3222 if (info->result == GNOME_VFS_OK) {
3223 GError *error = NULL;
3224 gboolean decode_in_provider;
3226 ModestAccountMgr *mgr;
3227 const gchar *account;
3228 ModestProtocol *protocol = NULL;
3230 stream = tny_vfs_stream_new (handle);
3232 decode_in_provider = FALSE;
3233 mgr = modest_runtime_get_account_mgr ();
3234 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3235 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3236 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3237 decode_in_provider =
3238 modest_account_protocol_decode_part_to_stream (
3239 MODEST_ACCOUNT_PROTOCOL (protocol),
3247 if (!decode_in_provider)
3248 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3251 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3253 if (error && (error->domain == TNY_ERROR_DOMAIN) &&
3254 (error->code == TNY_IO_ERROR_WRITE) &&
3255 (errno == ENOSPC)) {
3256 info->result = GNOME_VFS_ERROR_NO_SPACE;
3258 info->result = GNOME_VFS_ERROR_IO;
3261 g_object_unref (G_OBJECT (stream));
3263 g_warning ("Could not create save attachment %s: %s\n",
3264 pair->filename, gnome_vfs_result_to_string (info->result));
3267 /* Go on saving remaining files */
3268 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3269 if (info->pairs != NULL) {
3270 save_mime_part_to_file (info);
3272 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3279 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3280 SaveMimePartInfo *info)
3282 gboolean is_ok = TRUE;
3283 gint replaced_files = 0;
3284 const GList *files = info->pairs;
3285 const GList *iter, *to_replace = NULL;
3287 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3288 SaveMimePartPair *pair = iter->data;
3289 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3291 if (modest_utils_file_exists (unescaped)) {
3293 if (replaced_files == 1)
3298 if (replaced_files) {
3301 if (replaced_files == 1) {
3302 SaveMimePartPair *pair = to_replace->data;
3303 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3304 gchar *escaped_basename, *message;
3306 escaped_basename = g_uri_unescape_string (basename, NULL);
3307 message = g_strdup_printf ("%s\n%s",
3309 (escaped_basename) ? escaped_basename : "");
3310 response = modest_platform_run_confirmation_dialog (parent, message);
3312 g_free (escaped_basename);
3314 response = modest_platform_run_confirmation_dialog (parent,
3315 _FM_REPLACE_MULTIPLE);
3317 if (response != GTK_RESPONSE_OK)
3322 save_mime_part_info_free (info, TRUE);
3324 /* Start progress and launch thread */
3325 set_progress_hint (info->window, TRUE);
3326 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3331 typedef struct _SaveAttachmentsInfo {
3332 TnyList *attachments_list;
3333 ModestMsgViewWindow *window;
3334 } SaveAttachmentsInfo;
3337 save_attachments_response (GtkDialog *dialog,
3341 TnyList *mime_parts;
3343 GList *files_to_save = NULL;
3344 gchar *current_folder;
3345 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3347 mime_parts = TNY_LIST (sa_info->attachments_list);
3349 if (arg1 != GTK_RESPONSE_OK)
3352 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3353 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3354 if (current_folder && *current_folder != '\0') {
3356 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3357 current_folder,&err);
3359 g_debug ("Error storing latest used folder: %s", err->message);
3363 g_free (current_folder);
3365 if (!modest_utils_folder_writable (chooser_uri)) {
3366 const gchar *err_msg;
3368 #ifdef MODEST_PLATFORM_MAEMO
3369 if (modest_maemo_utils_in_usb_mode ()) {
3370 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3372 err_msg = _FM_READ_ONLY_LOCATION;
3375 err_msg = _FM_READ_ONLY_LOCATION;
3377 modest_platform_system_banner (NULL, NULL, err_msg);
3381 iter = tny_list_create_iterator (mime_parts);
3382 while (!tny_iterator_is_done (iter)) {
3383 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3385 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3386 !tny_mime_part_is_purged (mime_part) &&
3387 (tny_mime_part_get_filename (mime_part) != NULL)) {
3388 SaveMimePartPair *pair;
3390 pair = g_slice_new0 (SaveMimePartPair);
3392 if (tny_list_get_length (mime_parts) > 1) {
3394 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3395 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3398 pair->filename = g_strdup (chooser_uri);
3400 pair->part = mime_part;
3401 files_to_save = g_list_prepend (files_to_save, pair);
3403 tny_iterator_next (iter);
3405 g_object_unref (iter);
3408 if (files_to_save != NULL) {
3409 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3410 info->pairs = files_to_save;
3411 info->result = TRUE;
3412 info->uri = g_strdup (chooser_uri);
3413 info->window = g_object_ref (sa_info->window);
3414 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3416 g_free (chooser_uri);
3419 /* Free and close the dialog */
3420 g_object_unref (mime_parts);
3421 g_object_unref (sa_info->window);
3422 g_slice_free (SaveAttachmentsInfo, sa_info);
3423 gtk_widget_destroy (GTK_WIDGET (dialog));
3427 msg_is_attachment (TnyList *mime_parts)
3430 gboolean retval = FALSE;
3432 if (tny_list_get_length (mime_parts) > 1)
3435 iter = tny_list_create_iterator (mime_parts);
3437 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3439 if (TNY_IS_MSG (part))
3441 g_object_unref (part);
3443 g_object_unref (iter);
3449 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3450 TnyList *mime_parts)
3452 ModestMsgViewWindowPrivate *priv;
3453 GtkWidget *save_dialog = NULL;
3454 gchar *conf_folder = NULL;
3455 gchar *filename = NULL;
3456 gchar *save_multiple_str = NULL;
3457 const gchar *root_folder = "file:///";
3459 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3460 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3462 if (mime_parts == NULL) {
3463 gboolean allow_msgs = FALSE;
3465 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3466 * selection available */
3467 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3469 /* Check if the message is composed by an unique MIME
3470 part whose content disposition is attachment. There
3471 could be messages like this:
3473 Date: Tue, 12 Jan 2010 20:40:59 +0000
3474 From: <sender@example.org>
3475 To: <recipient@example.org>
3477 Content-Type: image/jpeg
3478 Content-Disposition: attachment; filename="bug7718.jpeg"
3480 whose unique MIME part is the message itself whose
3481 content disposition is attachment
3483 if (mime_parts && msg_is_attachment (mime_parts))
3486 if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, allow_msgs)) {
3487 g_object_unref (mime_parts);
3491 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3493 g_object_unref (mime_parts);
3499 g_object_ref (mime_parts);
3502 /* prepare dialog */
3503 if (tny_list_get_length (mime_parts) == 1) {
3505 /* only one attachment selected */
3506 iter = tny_list_create_iterator (mime_parts);
3507 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3508 g_object_unref (iter);
3509 if (!modest_tny_mime_part_is_msg (mime_part) &&
3510 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3511 !tny_mime_part_is_purged (mime_part)) {
3512 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3514 /* TODO: show any error? */
3515 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3516 g_object_unref (mime_parts);
3519 g_object_unref (mime_part);
3521 gint num = tny_list_get_length (mime_parts);
3522 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3523 "sfil_va_number_of_objects_attachment",
3524 "sfil_va_number_of_objects_attachments",
3528 /* Creation of hildon file chooser dialog for saving */
3529 save_dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
3531 (GtkWindow *) window,
3532 GTK_FILE_CHOOSER_ACTION_SAVE);
3534 /* Get last used folder */
3535 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3536 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3538 /* File chooser stops working if we select "file:///" as current folder */
3539 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3540 g_free (conf_folder);
3544 if (conf_folder && conf_folder[0] != '\0') {
3545 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3548 /* Set the default folder to documents folder */
3549 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3552 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3554 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3555 g_free (docs_folder);
3557 g_free (conf_folder);
3561 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3566 /* if multiple, set multiple string */
3567 if (save_multiple_str) {
3568 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3569 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM_SAVE_OBJECT_FILES);
3570 g_free (save_multiple_str);
3573 /* We must run this asynchronously, because the hildon dialog
3574 performs a gtk_dialog_run by itself which leads to gdk
3576 SaveAttachmentsInfo *sa_info;
3577 sa_info = g_slice_new (SaveAttachmentsInfo);
3578 sa_info->attachments_list = mime_parts;
3579 sa_info->window = g_object_ref (window);
3580 g_signal_connect (save_dialog, "response",
3581 G_CALLBACK (save_attachments_response), sa_info);
3583 gtk_widget_show_all (save_dialog);
3587 show_remove_attachment_information (gpointer userdata)
3589 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3590 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3592 /* We're outside the main lock */
3593 gdk_threads_enter ();
3595 if (priv->remove_attachment_banner != NULL) {
3596 gtk_widget_destroy (priv->remove_attachment_banner);
3597 g_object_unref (priv->remove_attachment_banner);
3600 priv->remove_attachment_banner = g_object_ref (
3601 modest_platform_animation_banner (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3603 gdk_threads_leave ();
3609 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3611 ModestMsgViewWindowPrivate *priv;
3612 TnyList *mime_parts = NULL, *tmp;
3613 gchar *confirmation_message;
3619 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3620 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3622 #ifdef MODEST_TOOLKIT_HILDON2
3623 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3624 * because we don't have selection
3626 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3628 /* Remove already purged messages from mime parts list. We use
3629 a copy of the list to remove items in the original one */
3630 tmp = tny_list_copy (mime_parts);
3631 iter = tny_list_create_iterator (tmp);
3632 while (!tny_iterator_is_done (iter)) {
3633 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3634 if (tny_mime_part_is_purged (part))
3635 tny_list_remove (mime_parts, (GObject *) part);
3637 g_object_unref (part);
3638 tny_iterator_next (iter);
3640 g_object_unref (tmp);
3641 g_object_unref (iter);
3643 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3644 tny_list_get_length (mime_parts) == 0) {
3645 g_object_unref (mime_parts);
3649 /* In gtk we get only selected attachments for the operation.
3651 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
3653 /* Remove already purged messages from mime parts list. We use
3654 a copy of the list to remove items in the original one */
3655 tmp = tny_list_copy (mime_parts);
3656 iter = tny_list_create_iterator (tmp);
3657 while (!tny_iterator_is_done (iter)) {
3658 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3659 if (tny_mime_part_is_purged (part))
3660 tny_list_remove (mime_parts, (GObject *) part);
3662 g_object_unref (part);
3663 tny_iterator_next (iter);
3665 g_object_unref (tmp);
3666 g_object_unref (iter);
3668 if (tny_list_get_length (mime_parts) == 0) {
3669 g_object_unref (mime_parts);
3674 n_attachments = tny_list_get_length (mime_parts);
3675 if (n_attachments == 1) {
3679 iter = tny_list_create_iterator (mime_parts);
3680 part = (TnyMimePart *) tny_iterator_get_current (iter);
3681 g_object_unref (iter);
3682 if (modest_tny_mime_part_is_msg (part)) {
3684 header = tny_msg_get_header (TNY_MSG (part));
3685 filename = tny_header_dup_subject (header);
3686 g_object_unref (header);
3687 if (filename == NULL)
3688 filename = g_strdup (_("mail_va_no_subject"));
3690 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3692 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3694 g_object_unref (part);
3696 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3697 "mcen_nc_purge_files_text",
3698 n_attachments), n_attachments);
3700 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3701 confirmation_message);
3702 g_free (confirmation_message);
3704 if (response != GTK_RESPONSE_OK) {
3705 g_object_unref (mime_parts);
3709 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3711 iter = tny_list_create_iterator (mime_parts);
3712 while (!tny_iterator_is_done (iter)) {
3715 part = (TnyMimePart *) tny_iterator_get_current (iter);
3716 tny_mime_part_set_purged (TNY_MIME_PART (part));
3717 g_object_unref (part);
3718 tny_iterator_next (iter);
3720 g_object_unref (iter);
3722 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3723 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3724 tny_msg_rewrite_cache (msg);
3725 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3726 g_object_unref (msg);
3727 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3729 g_object_unref (mime_parts);
3731 if (priv->purge_timeout > 0) {
3732 g_source_remove (priv->purge_timeout);
3733 priv->purge_timeout = 0;
3736 if (priv->remove_attachment_banner) {
3737 gtk_widget_destroy (priv->remove_attachment_banner);
3738 g_object_unref (priv->remove_attachment_banner);
3739 priv->remove_attachment_banner = NULL;
3745 update_window_title (ModestMsgViewWindow *window)
3747 ModestMsgViewWindowPrivate *priv;
3749 TnyHeader *header = NULL;
3750 gchar *subject = NULL;
3752 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3754 /* Note that if the window is closed while we're retrieving
3755 the message, this widget could de deleted */
3756 if (!priv->msg_view)
3759 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3761 if (priv->other_body) {
3764 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3766 g_strstrip (description);
3767 subject = description;
3769 } else if (msg != NULL) {
3770 header = tny_msg_get_header (msg);
3771 subject = tny_header_dup_subject (header);
3772 g_object_unref (header);
3773 g_object_unref (msg);
3776 if ((subject == NULL)||(subject[0] == '\0')) {
3778 subject = g_strdup (_("mail_va_no_subject"));
3781 modest_window_set_title (MODEST_WINDOW (window), subject);
3786 on_move_focus (GtkWidget *widget,
3787 GtkDirectionType direction,
3790 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3794 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3796 GnomeVFSResult result;
3797 GnomeVFSHandle *handle = NULL;
3798 GnomeVFSFileInfo *info = NULL;
3801 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3802 if (result != GNOME_VFS_OK) {
3807 info = gnome_vfs_file_info_new ();
3808 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3809 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3810 /* We put a "safe" default size for going to cache */
3811 *expected_size = (300*1024);
3813 *expected_size = info->size;
3815 gnome_vfs_file_info_unref (info);
3817 stream = tny_vfs_stream_new (handle);
3826 TnyStream *output_stream;
3827 GtkWidget *msg_view;
3832 on_fetch_image_timeout_refresh_view (gpointer userdata)
3834 ModestMsgViewWindowPrivate *priv;
3836 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3837 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3838 /* Note that priv->msg_view is set to NULL when this window is
3840 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3841 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3843 priv->fetch_image_redraw_handler = 0;
3844 g_object_unref (userdata);
3849 on_fetch_image_idle_refresh_view (gpointer userdata)
3852 FetchImageData *fidata = (FetchImageData *) userdata;
3854 gdk_threads_enter ();
3855 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3856 ModestMsgViewWindowPrivate *priv;
3858 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3859 priv->fetching_images--;
3860 if (priv->fetch_image_redraw_handler == 0) {
3861 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3865 gdk_threads_leave ();
3867 g_object_unref (fidata->msg_view);
3868 g_object_unref (fidata->window);
3869 g_slice_free (FetchImageData, fidata);
3874 on_fetch_image_thread (gpointer userdata)
3876 FetchImageData *fidata = (FetchImageData *) userdata;
3877 TnyStreamCache *cache;
3878 TnyStream *cache_stream;
3880 cache = modest_runtime_get_images_cache ();
3882 tny_stream_cache_get_stream (cache,
3884 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3885 (gpointer) fidata->uri);
3886 g_free (fidata->cache_id);
3887 g_free (fidata->uri);
3889 if (cache_stream != NULL) {
3892 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3895 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3896 if (G_UNLIKELY (nb_read < 0)) {
3898 } else if (G_LIKELY (nb_read > 0)) {
3899 gssize nb_written = 0;
3901 while (G_UNLIKELY (nb_written < nb_read)) {
3904 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3905 nb_read - nb_written);
3906 if (G_UNLIKELY (len < 0))
3912 tny_stream_close (cache_stream);
3913 g_object_unref (cache_stream);
3916 tny_stream_close (fidata->output_stream);
3917 g_object_unref (fidata->output_stream);
3919 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3925 on_fetch_image (ModestMsgView *msgview,
3928 ModestMsgViewWindow *window)
3930 const gchar *current_account;
3931 ModestMsgViewWindowPrivate *priv;
3932 FetchImageData *fidata;
3934 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3936 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3938 fidata = g_slice_new0 (FetchImageData);
3939 fidata->msg_view = g_object_ref (msgview);
3940 fidata->window = g_object_ref (window);
3941 fidata->uri = g_strdup (uri);
3942 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3943 fidata->output_stream = g_object_ref (stream);
3945 priv->fetching_images++;
3946 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3947 g_object_unref (fidata->output_stream);
3948 g_free (fidata->cache_id);
3949 g_free (fidata->uri);
3950 g_object_unref (fidata->msg_view);
3951 g_slice_free (FetchImageData, fidata);
3952 tny_stream_close (stream);
3953 priv->fetching_images--;
3954 update_progress_hint (window);
3957 update_progress_hint (window);
3963 setup_menu (ModestMsgViewWindow *self)
3965 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3967 /* Settings menu buttons */
3968 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3969 MODEST_WINDOW_MENU_CALLBACK (modest_msg_view_window_show_isearch_toolbar),
3970 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3972 modest_window_add_to_menu (MODEST_WINDOW (self),
3973 dngettext(GETTEXT_PACKAGE,
3974 "mcen_me_move_message",
3975 "mcen_me_move_messages",
3978 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_move_to),
3979 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3981 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3982 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3983 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3985 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3986 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3987 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3989 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3990 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_save_attachments),
3991 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3992 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3993 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3994 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3996 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3997 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3998 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3999 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4000 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4001 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4003 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_ti_message_properties"), NULL,
4004 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_details),
4005 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
4009 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
4011 ModestMsgViewWindowPrivate *priv;
4012 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4013 GSList *recipients = NULL;
4016 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
4020 header = modest_msg_view_window_get_header (self);
4023 recipients = modest_tny_msg_header_get_all_recipients_list (header);
4024 g_object_unref (header);
4026 recipients = modest_tny_msg_get_all_recipients_list (msg);
4027 g_object_unref (msg);
4031 /* Offer the user to add recipients to the address book */
4032 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
4033 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
4038 _modest_msg_view_window_map_event (GtkWidget *widget,
4042 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
4044 update_progress_hint (self);
4050 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4052 ModestMsgViewWindowPrivate *priv;
4053 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4055 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4059 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4061 ModestMsgViewWindowPrivate *priv;
4062 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4064 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4066 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4070 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4072 ModestMsgViewWindowPrivate *priv;
4073 const gchar *msg_uid;
4074 TnyHeader *header = NULL;
4075 TnyFolder *folder = NULL;
4077 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4079 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4081 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4085 folder = tny_header_get_folder (header);
4086 g_object_unref (header);
4091 msg_uid = modest_msg_view_window_get_message_uid (self);
4093 GtkTreeRowReference *row_reference;
4095 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4096 row_reference = priv->row_reference;
4098 row_reference = NULL;
4100 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4101 g_warning ("Shouldn't happen, trying to reload a message failed");
4104 g_object_unref (folder);
4108 update_branding (ModestMsgViewWindow *self)
4110 const gchar *account;
4111 const gchar *mailbox;
4112 ModestAccountMgr *mgr;
4113 ModestProtocol *protocol = NULL;
4114 gchar *service_name = NULL;
4115 const GdkPixbuf *service_icon = NULL;
4116 ModestMsgViewWindowPrivate *priv;
4118 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4120 account = modest_window_get_active_account (MODEST_WINDOW (self));
4121 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4123 mgr = modest_runtime_get_account_mgr ();
4125 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4126 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4127 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4129 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4130 account, mailbox, MODEST_ICON_SIZE_SMALL);
4134 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4135 g_free (service_name);
4139 sync_flags (ModestMsgViewWindow *self)
4141 TnyHeader *header = NULL;
4143 header = modest_msg_view_window_get_header (self);
4145 TnyMsg *msg = modest_msg_view_window_get_message (self);
4147 header = tny_msg_get_header (msg);
4148 g_object_unref (msg);
4153 TnyFolder *folder = tny_header_get_folder (header);
4156 ModestMailOperation *mail_op;
4158 /* Sync folder, we need this to save the seen flag */
4159 mail_op = modest_mail_operation_new (NULL);
4160 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4162 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4163 g_object_unref (mail_op);
4164 g_object_unref (folder);
4166 g_object_unref (header);
4170 #ifdef MODEST_TOOLKIT_HILDON2
4172 on_realize (GtkWidget *widget,
4175 GdkDisplay *display;
4177 unsigned long val = 1;
4179 display = gdk_drawable_get_display (widget->window);
4180 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4181 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4182 GDK_WINDOW_XID (widget->window), atom,
4183 XA_INTEGER, 32, PropModeReplace,
4184 (unsigned char *) &val, 1);
4191 on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
4193 const gchar *account_name;
4194 ModestProtocolType proto_type;
4195 ModestProtocol *protocol;
4196 gboolean retval = FALSE;
4198 account_name = modest_window_get_active_account (MODEST_WINDOW (self));
4201 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
4204 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
4207 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4208 retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
4209 calendar_part, container);