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;
2231 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2232 if (canceled || !self || MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self)->msg_view == NULL ) {
2234 gtk_tree_row_reference_free (row_reference);
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);
2249 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2250 /* First we check if the parent is a folder window */
2251 if (priv->msg_uid && !modest_window_mgr_get_folder_window (MODEST_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2253 TnyAccount *account = NULL;
2254 GtkWidget *header_window = NULL;
2256 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2258 /* Get the account */
2260 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2263 if (is_merge || account) {
2264 TnyFolder *folder = NULL;
2266 /* Try to get the message, if it's already downloaded
2267 we don't need to connect */
2269 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2272 ModestTnyAccountStore *account_store;
2273 ModestTnyLocalFoldersAccount *local_folders_account;
2275 account_store = modest_runtime_get_account_store ();
2276 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2277 modest_tny_account_store_get_local_folders_account (account_store));
2278 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2279 g_object_unref (local_folders_account);
2281 if (account) g_object_unref (account);
2284 header_window = (GtkWidget *)
2285 modest_header_window_new (
2287 modest_window_get_active_account (MODEST_WINDOW (self)),
2288 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2289 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2290 MODEST_WINDOW (header_window),
2292 gtk_widget_destroy (GTK_WIDGET (header_window));
2294 gtk_widget_show_all (GTK_WIDGET (header_window));
2296 g_object_unref (folder);
2302 /* Restore window title */
2303 update_window_title (self);
2304 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2305 g_object_unref (self);
2310 /* Get the window */
2311 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2312 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2314 /* Update the row reference */
2315 if (priv->row_reference != NULL) {
2316 gtk_tree_row_reference_free (priv->row_reference);
2317 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2318 if (priv->next_row_reference != NULL) {
2319 gtk_tree_row_reference_free (priv->next_row_reference);
2321 if (priv->row_reference) {
2322 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2323 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2325 priv->next_row_reference = NULL;
2329 /* Mark header as read */
2330 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN)) {
2333 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2334 uid = modest_tny_folder_get_header_unique_id (header);
2335 modest_platform_emit_msg_read_changed_signal (uid, TRUE);
2339 /* Set new message */
2340 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2341 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2342 modest_msg_view_window_update_priority (self);
2343 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2344 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2345 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2348 /* Set the new message uid of the window */
2349 if (priv->msg_uid) {
2350 g_free (priv->msg_uid);
2351 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2354 /* Notify the observers */
2355 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2356 0, priv->header_model, priv->row_reference);
2358 /* Sync the flags if the message is not opened from a header
2359 model, i.e, if it's opened from a notification */
2360 if (!priv->header_model)
2364 g_object_unref (self);
2366 gtk_tree_row_reference_free (row_reference);
2370 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2372 ModestMsgViewWindowPrivate *priv;
2374 TnyFolderType folder_type;
2376 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2378 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2380 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2384 folder = tny_msg_get_folder (msg);
2386 folder_type = modest_tny_folder_guess_folder_type (folder);
2387 g_object_unref (folder);
2389 g_object_unref (msg);
2397 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2399 ModestMsgViewWindowPrivate *priv;
2400 TnyHeader *header = NULL;
2401 TnyHeaderFlags flags = 0;
2403 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2405 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2407 GtkTreePath *path = NULL;
2409 path = gtk_tree_row_reference_get_path (priv->row_reference);
2410 g_return_if_fail (path != NULL);
2411 gtk_tree_model_get_iter (priv->header_model,
2413 gtk_tree_row_reference_get_path (priv->row_reference));
2415 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2417 gtk_tree_path_free (path);
2420 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2422 header = tny_msg_get_header (msg);
2423 g_object_unref (msg);
2428 flags = tny_header_get_flags (header);
2429 g_object_unref(G_OBJECT(header));
2432 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2437 toolbar_resize (ModestMsgViewWindow *self)
2439 ModestMsgViewWindowPrivate *priv = NULL;
2440 ModestWindowPrivate *parent_priv = NULL;
2442 gint static_button_size;
2443 ModestWindowMgr *mgr;
2445 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2446 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2447 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2449 mgr = modest_runtime_get_window_mgr ();
2450 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2452 if (parent_priv->toolbar) {
2453 /* Set expandable and homogeneous tool buttons */
2454 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2455 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2456 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2457 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2458 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2459 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2460 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2461 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2462 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2463 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2464 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2465 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2466 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2467 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2468 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2469 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2470 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2471 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2477 modest_msg_view_window_show_toolbar (ModestWindow *self,
2478 gboolean show_toolbar)
2480 ModestMsgViewWindowPrivate *priv = NULL;
2481 ModestWindowPrivate *parent_priv;
2483 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2484 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2486 /* Set optimized view status */
2487 priv->optimized_view = !show_toolbar;
2489 if (!parent_priv->toolbar) {
2490 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2493 #ifdef MODEST_TOOLKIT_HILDON2
2494 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2496 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), GTK_ICON_SIZE_LARGE_TOOLBAR);
2498 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2500 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2501 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2502 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2504 modest_window_add_toolbar (MODEST_WINDOW (self),
2505 GTK_TOOLBAR (parent_priv->toolbar));
2510 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2511 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2512 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2514 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2515 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2516 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2518 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2521 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2522 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2527 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2529 ModestMsgViewWindow *window)
2531 if (!GTK_WIDGET_VISIBLE (window))
2534 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2538 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2540 ModestMsgViewWindowPrivate *priv;
2542 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2543 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2545 return priv->progress_hint;
2549 observers_empty (ModestMsgViewWindow *self)
2552 ModestMsgViewWindowPrivate *priv;
2553 gboolean is_empty = TRUE;
2554 guint pending_ops = 0;
2556 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2557 tmp = priv->progress_widgets;
2559 /* Check all observers */
2560 while (tmp && is_empty) {
2561 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2562 is_empty = pending_ops == 0;
2564 tmp = g_slist_next(tmp);
2571 on_account_removed (TnyAccountStore *account_store,
2572 TnyAccount *account,
2575 /* Do nothing if it's a transport account, because we only
2576 show the messages of a store account */
2577 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2578 const gchar *parent_acc = NULL;
2579 const gchar *our_acc = NULL;
2581 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2582 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2584 /* Close this window if I'm showing a message of the removed account */
2585 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2586 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2591 on_mail_operation_started (ModestMailOperation *mail_op,
2594 ModestMsgViewWindow *self;
2595 ModestMailOperationTypeOperation op_type;
2597 ModestMsgViewWindowPrivate *priv;
2598 GObject *source = NULL;
2600 self = MODEST_MSG_VIEW_WINDOW (user_data);
2601 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2602 op_type = modest_mail_operation_get_type_operation (mail_op);
2603 tmp = priv->progress_widgets;
2604 source = modest_mail_operation_get_source(mail_op);
2605 if (G_OBJECT (self) == source) {
2606 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2607 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2608 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2609 set_progress_hint (self, TRUE);
2611 modest_progress_object_add_operation (
2612 MODEST_PROGRESS_OBJECT (tmp->data),
2614 tmp = g_slist_next (tmp);
2618 g_object_unref (source);
2620 /* Update dimming rules */
2621 check_dimming_rules_after_change (self);
2625 on_mail_operation_finished (ModestMailOperation *mail_op,
2628 ModestMsgViewWindow *self;
2629 ModestMailOperationTypeOperation op_type;
2631 ModestMsgViewWindowPrivate *priv;
2633 self = MODEST_MSG_VIEW_WINDOW (user_data);
2634 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2635 op_type = modest_mail_operation_get_type_operation (mail_op);
2636 tmp = priv->progress_widgets;
2638 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2639 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2640 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2642 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2644 tmp = g_slist_next (tmp);
2647 /* If no more operations are being observed, NORMAL mode is enabled again */
2648 if (observers_empty (self)) {
2649 set_progress_hint (self, FALSE);
2653 /* Update dimming rules. We have to do this right here
2654 and not in view_msg_cb because at that point the
2655 transfer mode is still enabled so the dimming rule
2656 won't let the user delete the message that has been
2657 readed for example */
2658 check_dimming_rules_after_change (self);
2662 on_queue_changed (ModestMailOperationQueue *queue,
2663 ModestMailOperation *mail_op,
2664 ModestMailOperationQueueNotification type,
2665 ModestMsgViewWindow *self)
2667 ModestMsgViewWindowPrivate *priv;
2669 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2671 /* If this operations was created by another window, do nothing */
2672 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2675 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2676 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2678 "operation-started",
2679 G_CALLBACK (on_mail_operation_started),
2681 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2683 "operation-finished",
2684 G_CALLBACK (on_mail_operation_finished),
2686 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2687 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2689 "operation-started");
2690 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2692 "operation-finished");
2697 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2699 ModestMsgViewWindowPrivate *priv;
2700 TnyList *selected_attachments = NULL;
2702 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2703 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2705 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2706 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2708 return selected_attachments;
2712 ModestMsgViewWindow *self;
2714 gchar *attachment_uid;
2715 } DecodeAsyncHelper;
2718 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2724 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2725 const gchar *content_type;
2726 ModestMsgViewWindowPrivate *priv;
2728 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2730 if (cancelled || err) {
2733 if ((err->domain == TNY_ERROR_DOMAIN) &&
2734 (err->code == TNY_IO_ERROR_WRITE) &&
2735 (errno == ENOSPC)) {
2736 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2738 msg = g_strdup (_("mail_ib_file_operation_failed"));
2740 modest_platform_information_banner (NULL, NULL, msg);
2746 /* It could happen that the window was closed. So we
2747 assume it is a cancelation */
2748 if (!GTK_WIDGET_VISIBLE (helper->self))
2751 /* Remove the progress hint */
2752 set_progress_hint (helper->self, FALSE);
2754 content_type = tny_mime_part_get_content_type (mime_part);
2755 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2756 ModestWindowMgr *mgr;
2757 ModestWindow *msg_win = NULL;
2760 const gchar *mailbox;
2761 TnyStream *file_stream;
2764 fd = g_open (helper->file_path, O_RDONLY, 0644);
2767 file_stream = tny_fs_stream_new (fd);
2769 mgr = modest_runtime_get_window_mgr ();
2771 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2772 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2775 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2777 msg = tny_camel_msg_new ();
2778 tny_camel_msg_parse ((TnyCamelMsg *) msg, file_stream);
2781 top_msg = g_object_ref (priv->top_msg);
2783 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2785 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2786 account, mailbox, helper->attachment_uid);
2787 if (top_msg) g_object_unref (top_msg);
2788 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2789 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2790 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2791 gtk_widget_show_all (GTK_WIDGET (msg_win));
2793 gtk_widget_destroy (GTK_WIDGET (msg_win));
2794 g_object_unref (msg);
2795 g_object_unref (file_stream);
2797 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2802 /* make the file read-only */
2803 g_chmod(helper->file_path, 0444);
2805 /* Activate the file */
2806 modest_platform_activate_file (helper->file_path, content_type);
2811 g_object_unref (helper->self);
2812 g_free (helper->file_path);
2813 g_free (helper->attachment_uid);
2814 g_slice_free (DecodeAsyncHelper, helper);
2818 view_attachment_connect_handler (gboolean canceled,
2820 GtkWindow *parent_window,
2821 TnyAccount *account,
2825 if (canceled || err) {
2826 g_object_unref (part);
2830 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2832 g_object_unref (part);
2836 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2837 TnyMimePart *mime_part)
2839 ModestMsgViewWindowPrivate *priv;
2840 const gchar *msg_uid;
2841 gchar *attachment_uid = NULL;
2842 gint attachment_index = 0;
2843 TnyList *attachments;
2845 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2846 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2847 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2849 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2850 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2851 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2852 g_object_unref (attachments);
2854 if (msg_uid && attachment_index >= 0) {
2855 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2858 if (mime_part == NULL) {
2859 gboolean error = FALSE;
2860 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2861 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2863 } else if (tny_list_get_length (selected_attachments) > 1) {
2864 modest_platform_system_banner (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2868 iter = tny_list_create_iterator (selected_attachments);
2869 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2870 g_object_unref (iter);
2872 if (selected_attachments)
2873 g_object_unref (selected_attachments);
2878 g_object_ref (mime_part);
2881 if (tny_mime_part_is_purged (mime_part))
2884 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2885 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2887 TnyAccount *account;
2889 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2891 /* Get the account */
2893 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2896 if (!tny_device_is_online (modest_runtime_get_device())) {
2897 modest_platform_connect_and_perform ((ModestWindow *) window,
2899 TNY_ACCOUNT (account),
2900 (ModestConnectedPerformer) view_attachment_connect_handler,
2901 g_object_ref (mime_part));
2906 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2907 gchar *filepath = NULL;
2908 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2909 gboolean show_error_banner = FALSE;
2910 TnyFsStream *temp_stream = NULL;
2911 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2914 if (temp_stream != NULL) {
2915 ModestAccountMgr *mgr;
2916 DecodeAsyncHelper *helper;
2917 gboolean decode_in_provider;
2918 ModestProtocol *protocol;
2919 const gchar *account;
2921 /* Activate progress hint */
2922 set_progress_hint (window, TRUE);
2924 helper = g_slice_new0 (DecodeAsyncHelper);
2925 helper->self = g_object_ref (window);
2926 helper->file_path = g_strdup (filepath);
2927 helper->attachment_uid = g_strdup (attachment_uid);
2929 decode_in_provider = FALSE;
2930 mgr = modest_runtime_get_account_mgr ();
2931 account = modest_window_get_active_account (MODEST_WINDOW (window));
2932 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2933 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2935 uri = g_strconcat ("file://", filepath, NULL);
2936 decode_in_provider =
2937 modest_account_protocol_decode_part_to_stream_async (
2938 MODEST_ACCOUNT_PROTOCOL (protocol),
2941 TNY_STREAM (temp_stream),
2942 on_decode_to_stream_async_handler,
2949 if (!decode_in_provider)
2950 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2951 on_decode_to_stream_async_handler,
2954 g_object_unref (temp_stream);
2955 /* NOTE: files in the temporary area will be automatically
2956 * cleaned after some time if they are no longer in use */
2959 const gchar *content_type;
2960 /* the file may already exist but it isn't writable,
2961 * let's try to open it anyway */
2962 content_type = tny_mime_part_get_content_type (mime_part);
2963 modest_platform_activate_file (filepath, content_type);
2965 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2966 show_error_banner = TRUE;
2971 if (show_error_banner)
2972 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2973 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2974 ModestWindowMgr *mgr;
2975 ModestWindow *msg_win = NULL;
2976 TnyMsg *current_msg;
2980 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2981 mgr = modest_runtime_get_window_mgr ();
2982 header = tny_msg_get_header (TNY_MSG (current_msg));
2983 found = modest_window_mgr_find_registered_message_uid (mgr,
2988 g_debug ("window for this body is already being created");
2992 /* it's not found, so create a new window for it */
2993 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2994 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2995 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2997 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3000 top_msg = g_object_ref (priv->top_msg);
3002 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3004 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
3005 account, mailbox, attachment_uid);
3007 if (top_msg) g_object_unref (top_msg);
3009 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3010 modest_window_get_zoom (MODEST_WINDOW (window)));
3011 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3012 gtk_widget_show_all (GTK_WIDGET (msg_win));
3014 gtk_widget_destroy (GTK_WIDGET (msg_win));
3016 g_object_unref (current_msg);
3018 /* message attachment */
3019 TnyHeader *header = NULL;
3020 ModestWindowMgr *mgr;
3021 ModestWindow *msg_win = NULL;
3024 header = tny_msg_get_header (TNY_MSG (mime_part));
3025 mgr = modest_runtime_get_window_mgr ();
3026 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3029 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3030 * thus, we don't do anything */
3031 g_debug ("window for is already being created");
3034 /* it's not found, so create a new window for it */
3035 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3036 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3037 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3039 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3041 top_msg = g_object_ref (priv->top_msg);
3043 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3044 msg_win = modest_msg_view_window_new_for_attachment (
3045 TNY_MSG (mime_part), top_msg, account,
3046 mailbox, attachment_uid);
3047 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3048 modest_window_get_zoom (MODEST_WINDOW (window)));
3049 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3050 gtk_widget_show_all (GTK_WIDGET (msg_win));
3052 gtk_widget_destroy (GTK_WIDGET (msg_win));
3058 g_free (attachment_uid);
3060 g_object_unref (mime_part);
3072 GnomeVFSResult result;
3074 ModestMsgViewWindow *window;
3077 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3078 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3079 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3080 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3083 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3087 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3088 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3089 g_free (pair->filename);
3090 g_object_unref (pair->part);
3091 g_slice_free (SaveMimePartPair, pair);
3093 g_list_free (info->pairs);
3096 g_object_unref (info->window);
3097 info->window = NULL;
3099 g_slice_free (SaveMimePartInfo, info);
3104 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3106 /* This is a GDK lock because we are an idle callback and
3107 * modest_platform_system_banner is or does Gtk+ code */
3109 gdk_threads_enter (); /* CHECKED */
3110 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3112 } else if (info->result == GNOME_VFS_OK) {
3113 modest_platform_system_banner (NULL, NULL, _CS_SAVED);
3114 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3117 /* Check if the uri belongs to the external mmc */
3118 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3119 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3121 msg = g_strdup (_KR("cerm_memory_card_full"));
3122 modest_platform_information_banner (NULL, NULL, msg);
3125 modest_platform_system_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
3127 set_progress_hint (info->window, FALSE);
3128 save_mime_part_info_free (info, FALSE);
3129 gdk_threads_leave (); /* CHECKED */
3135 save_mime_part_to_file_connect_handler (gboolean canceled,
3137 GtkWindow *parent_window,
3138 TnyAccount *account,
3139 SaveMimePartInfo *info)
3141 if (canceled || err) {
3142 if (canceled && !err) {
3143 info->result = GNOME_VFS_ERROR_CANCELLED;
3145 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3147 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3152 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3155 TnyAccount *account;
3156 ModestMsgViewWindowPrivate *priv;
3158 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3160 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3163 /* Get the account */
3165 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3168 modest_platform_connect_and_perform ((ModestWindow *) info->window,
3170 TNY_ACCOUNT (account),
3171 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3175 g_object_unref (account);
3181 save_mime_part_to_file (SaveMimePartInfo *info)
3183 GnomeVFSHandle *handle;
3185 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3187 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3188 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3189 gboolean check_online = TRUE;
3190 ModestMsgViewWindowPrivate *priv = NULL;
3192 /* Check if we really need to connect to save the mime part */
3193 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3194 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3195 check_online = FALSE;
3197 TnyAccountStore *acc_store;
3198 TnyAccount *account = NULL;
3200 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3201 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3204 if (tny_account_get_connection_status (account) ==
3205 TNY_CONNECTION_STATUS_CONNECTED)
3206 check_online = FALSE;
3207 g_object_unref (account);
3209 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3214 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3219 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3220 if (info->result == GNOME_VFS_OK) {
3221 GError *error = NULL;
3222 gboolean decode_in_provider;
3224 ModestAccountMgr *mgr;
3225 const gchar *account;
3226 ModestProtocol *protocol = NULL;
3228 stream = tny_vfs_stream_new (handle);
3230 decode_in_provider = FALSE;
3231 mgr = modest_runtime_get_account_mgr ();
3232 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3233 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3234 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3235 decode_in_provider =
3236 modest_account_protocol_decode_part_to_stream (
3237 MODEST_ACCOUNT_PROTOCOL (protocol),
3245 if (!decode_in_provider)
3246 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3249 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3251 if (error && (error->domain == TNY_ERROR_DOMAIN) &&
3252 (error->code == TNY_IO_ERROR_WRITE) &&
3253 (errno == ENOSPC)) {
3254 info->result = GNOME_VFS_ERROR_NO_SPACE;
3256 info->result = GNOME_VFS_ERROR_IO;
3259 g_object_unref (G_OBJECT (stream));
3261 g_warning ("Could not create save attachment %s: %s\n",
3262 pair->filename, gnome_vfs_result_to_string (info->result));
3265 /* Go on saving remaining files */
3266 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3267 if (info->pairs != NULL) {
3268 save_mime_part_to_file (info);
3270 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3277 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3278 SaveMimePartInfo *info)
3280 gboolean is_ok = TRUE;
3281 gint replaced_files = 0;
3282 const GList *files = info->pairs;
3283 const GList *iter, *to_replace = NULL;
3285 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3286 SaveMimePartPair *pair = iter->data;
3287 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3289 if (modest_utils_file_exists (unescaped)) {
3291 if (replaced_files == 1)
3296 if (replaced_files) {
3299 if (replaced_files == 1) {
3300 SaveMimePartPair *pair = to_replace->data;
3301 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3302 gchar *escaped_basename, *message;
3304 escaped_basename = g_uri_unescape_string (basename, NULL);
3305 message = g_strdup_printf ("%s\n%s",
3307 (escaped_basename) ? escaped_basename : "");
3308 response = modest_platform_run_confirmation_dialog (parent, message);
3310 g_free (escaped_basename);
3312 response = modest_platform_run_confirmation_dialog (parent,
3313 _FM_REPLACE_MULTIPLE);
3315 if (response != GTK_RESPONSE_OK)
3320 save_mime_part_info_free (info, TRUE);
3322 /* Start progress and launch thread */
3323 set_progress_hint (info->window, TRUE);
3324 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3329 typedef struct _SaveAttachmentsInfo {
3330 TnyList *attachments_list;
3331 ModestMsgViewWindow *window;
3332 } SaveAttachmentsInfo;
3335 save_attachments_response (GtkDialog *dialog,
3339 TnyList *mime_parts;
3341 GList *files_to_save = NULL;
3342 gchar *current_folder;
3343 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3345 mime_parts = TNY_LIST (sa_info->attachments_list);
3347 if (arg1 != GTK_RESPONSE_OK)
3350 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3351 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3352 if (current_folder && *current_folder != '\0') {
3354 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3355 current_folder,&err);
3357 g_debug ("Error storing latest used folder: %s", err->message);
3361 g_free (current_folder);
3363 if (!modest_utils_folder_writable (chooser_uri)) {
3364 const gchar *err_msg;
3366 #ifdef MODEST_PLATFORM_MAEMO
3367 if (modest_maemo_utils_in_usb_mode ()) {
3368 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3370 err_msg = _FM_READ_ONLY_LOCATION;
3373 err_msg = _FM_READ_ONLY_LOCATION;
3375 modest_platform_system_banner (NULL, NULL, err_msg);
3379 iter = tny_list_create_iterator (mime_parts);
3380 while (!tny_iterator_is_done (iter)) {
3381 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3383 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3384 !tny_mime_part_is_purged (mime_part) &&
3385 (tny_mime_part_get_filename (mime_part) != NULL)) {
3386 SaveMimePartPair *pair;
3388 pair = g_slice_new0 (SaveMimePartPair);
3390 if (tny_list_get_length (mime_parts) > 1) {
3392 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3393 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3396 pair->filename = g_strdup (chooser_uri);
3398 pair->part = mime_part;
3399 files_to_save = g_list_prepend (files_to_save, pair);
3401 tny_iterator_next (iter);
3403 g_object_unref (iter);
3406 if (files_to_save != NULL) {
3407 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3408 info->pairs = files_to_save;
3409 info->result = TRUE;
3410 info->uri = g_strdup (chooser_uri);
3411 info->window = g_object_ref (sa_info->window);
3412 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3414 g_free (chooser_uri);
3417 /* Free and close the dialog */
3418 g_object_unref (mime_parts);
3419 g_object_unref (sa_info->window);
3420 g_slice_free (SaveAttachmentsInfo, sa_info);
3421 gtk_widget_destroy (GTK_WIDGET (dialog));
3425 msg_is_attachment (TnyList *mime_parts)
3428 gboolean retval = FALSE;
3430 if (tny_list_get_length (mime_parts) > 1)
3433 iter = tny_list_create_iterator (mime_parts);
3435 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3437 if (TNY_IS_MSG (part))
3439 g_object_unref (part);
3441 g_object_unref (iter);
3447 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3448 TnyList *mime_parts)
3450 ModestMsgViewWindowPrivate *priv;
3451 GtkWidget *save_dialog = NULL;
3452 gchar *conf_folder = NULL;
3453 gchar *filename = NULL;
3454 gchar *save_multiple_str = NULL;
3455 const gchar *root_folder = "file:///";
3457 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3458 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3460 if (mime_parts == NULL) {
3461 gboolean allow_msgs = FALSE;
3463 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3464 * selection available */
3465 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3467 /* Check if the message is composed by an unique MIME
3468 part whose content disposition is attachment. There
3469 could be messages like this:
3471 Date: Tue, 12 Jan 2010 20:40:59 +0000
3472 From: <sender@example.org>
3473 To: <recipient@example.org>
3475 Content-Type: image/jpeg
3476 Content-Disposition: attachment; filename="bug7718.jpeg"
3478 whose unique MIME part is the message itself whose
3479 content disposition is attachment
3481 if (mime_parts && msg_is_attachment (mime_parts))
3484 if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, allow_msgs)) {
3485 g_object_unref (mime_parts);
3489 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3491 g_object_unref (mime_parts);
3497 g_object_ref (mime_parts);
3500 /* prepare dialog */
3501 if (tny_list_get_length (mime_parts) == 1) {
3503 /* only one attachment selected */
3504 iter = tny_list_create_iterator (mime_parts);
3505 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3506 g_object_unref (iter);
3507 if (!modest_tny_mime_part_is_msg (mime_part) &&
3508 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3509 !tny_mime_part_is_purged (mime_part)) {
3510 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3512 /* TODO: show any error? */
3513 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3514 g_object_unref (mime_parts);
3517 g_object_unref (mime_part);
3519 gint num = tny_list_get_length (mime_parts);
3520 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3521 "sfil_va_number_of_objects_attachment",
3522 "sfil_va_number_of_objects_attachments",
3526 /* Creation of hildon file chooser dialog for saving */
3527 save_dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
3529 (GtkWindow *) window,
3530 GTK_FILE_CHOOSER_ACTION_SAVE);
3532 /* Get last used folder */
3533 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3534 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3536 /* File chooser stops working if we select "file:///" as current folder */
3537 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3538 g_free (conf_folder);
3542 if (conf_folder && conf_folder[0] != '\0') {
3543 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3546 /* Set the default folder to documents folder */
3547 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3550 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3552 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3553 g_free (docs_folder);
3555 g_free (conf_folder);
3559 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3564 /* if multiple, set multiple string */
3565 if (save_multiple_str) {
3566 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3567 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM_SAVE_OBJECT_FILES);
3568 g_free (save_multiple_str);
3571 /* We must run this asynchronously, because the hildon dialog
3572 performs a gtk_dialog_run by itself which leads to gdk
3574 SaveAttachmentsInfo *sa_info;
3575 sa_info = g_slice_new (SaveAttachmentsInfo);
3576 sa_info->attachments_list = mime_parts;
3577 sa_info->window = g_object_ref (window);
3578 g_signal_connect (save_dialog, "response",
3579 G_CALLBACK (save_attachments_response), sa_info);
3581 gtk_widget_show_all (save_dialog);
3585 show_remove_attachment_information (gpointer userdata)
3587 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3588 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3590 /* We're outside the main lock */
3591 gdk_threads_enter ();
3593 if (priv->remove_attachment_banner != NULL) {
3594 gtk_widget_destroy (priv->remove_attachment_banner);
3595 g_object_unref (priv->remove_attachment_banner);
3598 priv->remove_attachment_banner = g_object_ref (
3599 modest_platform_animation_banner (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3601 gdk_threads_leave ();
3607 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3609 ModestMsgViewWindowPrivate *priv;
3610 TnyList *mime_parts = NULL, *tmp;
3611 gchar *confirmation_message;
3617 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3618 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3620 #ifdef MODEST_TOOLKIT_HILDON2
3621 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3622 * because we don't have selection
3624 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3626 /* Remove already purged messages from mime parts list. We use
3627 a copy of the list to remove items in the original one */
3628 tmp = tny_list_copy (mime_parts);
3629 iter = tny_list_create_iterator (tmp);
3630 while (!tny_iterator_is_done (iter)) {
3631 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3632 if (tny_mime_part_is_purged (part))
3633 tny_list_remove (mime_parts, (GObject *) part);
3635 g_object_unref (part);
3636 tny_iterator_next (iter);
3638 g_object_unref (tmp);
3639 g_object_unref (iter);
3641 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3642 tny_list_get_length (mime_parts) == 0) {
3643 g_object_unref (mime_parts);
3647 /* In gtk we get only selected attachments for the operation.
3649 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
3651 /* Remove already purged messages from mime parts list. We use
3652 a copy of the list to remove items in the original one */
3653 tmp = tny_list_copy (mime_parts);
3654 iter = tny_list_create_iterator (tmp);
3655 while (!tny_iterator_is_done (iter)) {
3656 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3657 if (tny_mime_part_is_purged (part))
3658 tny_list_remove (mime_parts, (GObject *) part);
3660 g_object_unref (part);
3661 tny_iterator_next (iter);
3663 g_object_unref (tmp);
3664 g_object_unref (iter);
3666 if (tny_list_get_length (mime_parts) == 0) {
3667 g_object_unref (mime_parts);
3672 n_attachments = tny_list_get_length (mime_parts);
3673 if (n_attachments == 1) {
3677 iter = tny_list_create_iterator (mime_parts);
3678 part = (TnyMimePart *) tny_iterator_get_current (iter);
3679 g_object_unref (iter);
3680 if (modest_tny_mime_part_is_msg (part)) {
3682 header = tny_msg_get_header (TNY_MSG (part));
3683 filename = tny_header_dup_subject (header);
3684 g_object_unref (header);
3685 if (filename == NULL)
3686 filename = g_strdup (_("mail_va_no_subject"));
3688 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3690 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3692 g_object_unref (part);
3694 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3695 "mcen_nc_purge_files_text",
3696 n_attachments), n_attachments);
3698 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3699 confirmation_message);
3700 g_free (confirmation_message);
3702 if (response != GTK_RESPONSE_OK) {
3703 g_object_unref (mime_parts);
3707 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3709 iter = tny_list_create_iterator (mime_parts);
3710 while (!tny_iterator_is_done (iter)) {
3713 part = (TnyMimePart *) tny_iterator_get_current (iter);
3714 tny_mime_part_set_purged (TNY_MIME_PART (part));
3715 g_object_unref (part);
3716 tny_iterator_next (iter);
3718 g_object_unref (iter);
3720 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3721 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3722 tny_msg_rewrite_cache (msg);
3723 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3724 g_object_unref (msg);
3725 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3727 g_object_unref (mime_parts);
3729 if (priv->purge_timeout > 0) {
3730 g_source_remove (priv->purge_timeout);
3731 priv->purge_timeout = 0;
3734 if (priv->remove_attachment_banner) {
3735 gtk_widget_destroy (priv->remove_attachment_banner);
3736 g_object_unref (priv->remove_attachment_banner);
3737 priv->remove_attachment_banner = NULL;
3743 update_window_title (ModestMsgViewWindow *window)
3745 ModestMsgViewWindowPrivate *priv;
3747 TnyHeader *header = NULL;
3748 gchar *subject = NULL;
3750 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3752 /* Note that if the window is closed while we're retrieving
3753 the message, this widget could de deleted */
3754 if (!priv->msg_view)
3757 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3759 if (priv->other_body) {
3762 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3764 g_strstrip (description);
3765 subject = description;
3767 } else if (msg != NULL) {
3768 header = tny_msg_get_header (msg);
3769 subject = tny_header_dup_subject (header);
3770 g_object_unref (header);
3771 g_object_unref (msg);
3774 if ((subject == NULL)||(subject[0] == '\0')) {
3776 subject = g_strdup (_("mail_va_no_subject"));
3779 modest_window_set_title (MODEST_WINDOW (window), subject);
3784 on_move_focus (GtkWidget *widget,
3785 GtkDirectionType direction,
3788 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3792 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3794 GnomeVFSResult result;
3795 GnomeVFSHandle *handle = NULL;
3796 GnomeVFSFileInfo *info = NULL;
3799 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3800 if (result != GNOME_VFS_OK) {
3805 info = gnome_vfs_file_info_new ();
3806 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3807 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3808 /* We put a "safe" default size for going to cache */
3809 *expected_size = (300*1024);
3811 *expected_size = info->size;
3813 gnome_vfs_file_info_unref (info);
3815 stream = tny_vfs_stream_new (handle);
3824 TnyStream *output_stream;
3825 GtkWidget *msg_view;
3830 on_fetch_image_timeout_refresh_view (gpointer userdata)
3832 ModestMsgViewWindowPrivate *priv;
3834 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3835 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3836 /* Note that priv->msg_view is set to NULL when this window is
3838 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3839 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3841 priv->fetch_image_redraw_handler = 0;
3842 g_object_unref (userdata);
3847 on_fetch_image_idle_refresh_view (gpointer userdata)
3850 FetchImageData *fidata = (FetchImageData *) userdata;
3852 gdk_threads_enter ();
3853 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3854 ModestMsgViewWindowPrivate *priv;
3856 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3857 priv->fetching_images--;
3858 if (priv->fetch_image_redraw_handler == 0) {
3859 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3863 gdk_threads_leave ();
3865 g_object_unref (fidata->msg_view);
3866 g_object_unref (fidata->window);
3867 g_slice_free (FetchImageData, fidata);
3872 on_fetch_image_thread (gpointer userdata)
3874 FetchImageData *fidata = (FetchImageData *) userdata;
3875 TnyStreamCache *cache;
3876 TnyStream *cache_stream;
3878 cache = modest_runtime_get_images_cache ();
3880 tny_stream_cache_get_stream (cache,
3882 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3883 (gpointer) fidata->uri);
3884 g_free (fidata->cache_id);
3885 g_free (fidata->uri);
3887 if (cache_stream != NULL) {
3890 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3893 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3894 if (G_UNLIKELY (nb_read < 0)) {
3896 } else if (G_LIKELY (nb_read > 0)) {
3897 gssize nb_written = 0;
3899 while (G_UNLIKELY (nb_written < nb_read)) {
3902 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3903 nb_read - nb_written);
3904 if (G_UNLIKELY (len < 0))
3910 tny_stream_close (cache_stream);
3911 g_object_unref (cache_stream);
3914 tny_stream_close (fidata->output_stream);
3915 g_object_unref (fidata->output_stream);
3917 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3923 on_fetch_image (ModestMsgView *msgview,
3926 ModestMsgViewWindow *window)
3928 const gchar *current_account;
3929 ModestMsgViewWindowPrivate *priv;
3930 FetchImageData *fidata;
3932 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3934 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3936 fidata = g_slice_new0 (FetchImageData);
3937 fidata->msg_view = g_object_ref (msgview);
3938 fidata->window = g_object_ref (window);
3939 fidata->uri = g_strdup (uri);
3940 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3941 fidata->output_stream = g_object_ref (stream);
3943 priv->fetching_images++;
3944 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3945 g_object_unref (fidata->output_stream);
3946 g_free (fidata->cache_id);
3947 g_free (fidata->uri);
3948 g_object_unref (fidata->msg_view);
3949 g_slice_free (FetchImageData, fidata);
3950 tny_stream_close (stream);
3951 priv->fetching_images--;
3952 update_progress_hint (window);
3955 update_progress_hint (window);
3961 setup_menu (ModestMsgViewWindow *self)
3963 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3965 /* Settings menu buttons */
3966 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3967 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3968 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3970 modest_window_add_to_menu (MODEST_WINDOW (self),
3971 dngettext(GETTEXT_PACKAGE,
3972 "mcen_me_move_message",
3973 "mcen_me_move_messages",
3976 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_move_to),
3977 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3979 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3980 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3981 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3982 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3983 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3984 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3986 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3987 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_save_attachments),
3988 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3989 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3990 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3991 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3993 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3994 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3995 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3997 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3998 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_details),
3999 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
4001 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), NULL,
4002 MODEST_WINDOW_MENU_CALLBACK (modest_msg_view_window_show_isearch_toolbar),
4003 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
4007 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
4009 ModestMsgViewWindowPrivate *priv;
4010 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4011 GSList *recipients = NULL;
4014 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
4018 header = modest_msg_view_window_get_header (self);
4021 recipients = modest_tny_msg_header_get_all_recipients_list (header);
4022 g_object_unref (header);
4024 recipients = modest_tny_msg_get_all_recipients_list (msg);
4025 g_object_unref (msg);
4029 /* Offer the user to add recipients to the address book */
4030 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
4031 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
4036 _modest_msg_view_window_map_event (GtkWidget *widget,
4040 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
4042 update_progress_hint (self);
4048 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4050 ModestMsgViewWindowPrivate *priv;
4051 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4053 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4057 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4059 ModestMsgViewWindowPrivate *priv;
4060 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4062 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4064 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4068 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4070 ModestMsgViewWindowPrivate *priv;
4071 const gchar *msg_uid;
4072 TnyHeader *header = NULL;
4073 TnyFolder *folder = NULL;
4075 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4077 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4079 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4083 folder = tny_header_get_folder (header);
4084 g_object_unref (header);
4089 msg_uid = modest_msg_view_window_get_message_uid (self);
4091 GtkTreeRowReference *row_reference;
4093 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4094 row_reference = priv->row_reference;
4096 row_reference = NULL;
4098 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4099 g_warning ("Shouldn't happen, trying to reload a message failed");
4102 g_object_unref (folder);
4106 update_branding (ModestMsgViewWindow *self)
4108 const gchar *account;
4109 const gchar *mailbox;
4110 ModestAccountMgr *mgr;
4111 ModestProtocol *protocol = NULL;
4112 gchar *service_name = NULL;
4113 const GdkPixbuf *service_icon = NULL;
4114 ModestMsgViewWindowPrivate *priv;
4116 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4118 account = modest_window_get_active_account (MODEST_WINDOW (self));
4119 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4121 mgr = modest_runtime_get_account_mgr ();
4123 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4124 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4125 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4127 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4128 account, mailbox, MODEST_ICON_SIZE_SMALL);
4132 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4133 g_free (service_name);
4137 sync_flags (ModestMsgViewWindow *self)
4139 TnyHeader *header = NULL;
4141 header = modest_msg_view_window_get_header (self);
4143 TnyMsg *msg = modest_msg_view_window_get_message (self);
4145 header = tny_msg_get_header (msg);
4146 g_object_unref (msg);
4151 TnyFolder *folder = tny_header_get_folder (header);
4154 ModestMailOperation *mail_op;
4156 /* Sync folder, we need this to save the seen flag */
4157 mail_op = modest_mail_operation_new (NULL);
4158 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4160 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4161 g_object_unref (mail_op);
4162 g_object_unref (folder);
4164 g_object_unref (header);
4168 #ifdef MODEST_TOOLKIT_HILDON2
4170 on_realize (GtkWidget *widget,
4173 GdkDisplay *display;
4175 unsigned long val = 1;
4177 display = gdk_drawable_get_display (widget->window);
4178 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4179 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4180 GDK_WINDOW_XID (widget->window), atom,
4181 XA_INTEGER, 32, PropModeReplace,
4182 (unsigned char *) &val, 1);
4189 on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
4191 const gchar *account_name;
4192 ModestProtocolType proto_type;
4193 ModestProtocol *protocol;
4194 gboolean retval = FALSE;
4196 account_name = modest_window_get_active_account (MODEST_WINDOW (self));
4199 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
4202 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
4205 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4206 retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
4207 calendar_part, container);