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);
254 static gboolean on_realize (GtkWidget *widget,
257 /* list my signals */
264 static const GtkActionEntry msg_view_toolbar_action_entries [] = {
267 { "ToolbarMessageReply", MODEST_STOCK_REPLY, N_("mcen_me_inbox_reply"), "<CTRL>R", NULL, G_CALLBACK (modest_ui_actions_on_reply) },
268 { "ToolbarMessageReplyAll", MODEST_STOCK_REPLY_ALL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
269 { "ToolbarMessageForward", MODEST_STOCK_FORWARD, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
270 { "ToolbarDeleteMessage", MODEST_STOCK_DELETE, N_("qgn_toolb_gene_deletebutton"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message_or_folder) },
271 { "ToolbarMessageBack", MODEST_TOOLBAR_ICON_PREV, N_("qgn_toolb_gene_back"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_prev) },
272 { "ToolbarMessageNext", MODEST_TOOLBAR_ICON_NEXT, N_("qgn_toolb_gene_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_next) },
273 { "ToolbarDownloadExternalImages", MODEST_TOOLBAR_ICON_DOWNLOAD_IMAGES, N_("mail_bd_external_images"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_fetch_images) },
276 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
277 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_isearch_toolbar), FALSE },
280 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
281 MODEST_TYPE_MSG_VIEW_WINDOW, \
282 ModestMsgViewWindowPrivate))
284 static GtkWindowClass *parent_class = NULL;
286 /* uncomment the following if you have defined any signals */
287 static guint signals[LAST_SIGNAL] = {0};
290 modest_msg_view_window_get_type (void)
292 static GType my_type = 0;
294 static const GTypeInfo my_info = {
295 sizeof(ModestMsgViewWindowClass),
296 NULL, /* base init */
297 NULL, /* base finalize */
298 (GClassInitFunc) modest_msg_view_window_class_init,
299 NULL, /* class finalize */
300 NULL, /* class data */
301 sizeof(ModestMsgViewWindow),
303 (GInstanceInitFunc) modest_msg_view_window_init,
306 #ifndef MODEST_TOOLKIT_HILDON2
307 my_type = g_type_register_static (MODEST_TYPE_SHELL_WINDOW,
308 "ModestMsgViewWindow",
311 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
312 "ModestMsgViewWindow",
316 static const GInterfaceInfo modest_header_view_observer_info =
318 (GInterfaceInitFunc) modest_header_view_observer_init,
319 NULL, /* interface_finalize */
320 NULL /* interface_data */
323 g_type_add_interface_static (my_type,
324 MODEST_TYPE_HEADER_VIEW_OBSERVER,
325 &modest_header_view_observer_info);
331 save_state (ModestWindow *self)
333 modest_widget_memory_save (modest_runtime_get_conf (),
335 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
339 modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
340 GtkScrollType scroll_type,
344 ModestMsgViewWindowPrivate *priv;
347 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
349 switch (scroll_type) {
350 case GTK_SCROLL_STEP_UP:
353 case GTK_SCROLL_STEP_DOWN:
356 case GTK_SCROLL_PAGE_UP:
359 case GTK_SCROLL_PAGE_DOWN:
362 case GTK_SCROLL_START:
373 modest_scrollable_scroll ((ModestScrollable *) priv->main_scroll, 0, step);
375 return (gboolean) step;
379 add_scroll_binding (GtkBindingSet *binding_set,
381 GtkScrollType scroll)
383 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
385 gtk_binding_entry_add_signal (binding_set, keyval, 0,
387 GTK_TYPE_SCROLL_TYPE, scroll,
388 G_TYPE_BOOLEAN, FALSE);
389 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
391 GTK_TYPE_SCROLL_TYPE, scroll,
392 G_TYPE_BOOLEAN, FALSE);
396 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
398 GObjectClass *gobject_class;
399 ModestWindowClass *modest_window_class;
400 GtkBindingSet *binding_set;
402 gobject_class = (GObjectClass*) klass;
403 modest_window_class = (ModestWindowClass *) klass;
405 parent_class = g_type_class_peek_parent (klass);
406 gobject_class->finalize = modest_msg_view_window_finalize;
408 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
409 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
410 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
411 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
412 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
413 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
415 modest_window_class->save_state_func = save_state;
417 klass->scroll_child = modest_msg_view_window_scroll_child;
419 signals[MSG_CHANGED_SIGNAL] =
420 g_signal_new ("msg-changed",
421 G_TYPE_FROM_CLASS (gobject_class),
423 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
425 modest_marshal_VOID__POINTER_POINTER,
426 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
428 signals[SCROLL_CHILD_SIGNAL] =
429 g_signal_new ("scroll-child",
430 G_TYPE_FROM_CLASS (gobject_class),
431 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
432 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
434 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
435 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
437 binding_set = gtk_binding_set_by_class (klass);
438 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
439 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
440 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
441 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
442 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
443 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
445 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
449 static void modest_header_view_observer_init(
450 ModestHeaderViewObserverIface *iface_class)
452 iface_class->update_func = modest_msg_view_window_update_model_replaced;
456 modest_msg_view_window_init (ModestMsgViewWindow *obj)
458 ModestMsgViewWindowPrivate *priv;
459 ModestWindowPrivate *parent_priv = NULL;
460 GtkActionGroup *action_group = NULL;
461 GError *error = NULL;
463 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
464 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
465 parent_priv->ui_manager = gtk_ui_manager_new();
467 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
468 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
470 /* Add common actions */
471 gtk_action_group_add_actions (action_group,
472 msg_view_toolbar_action_entries,
473 G_N_ELEMENTS (msg_view_toolbar_action_entries),
475 gtk_action_group_add_toggle_actions (action_group,
476 msg_view_toggle_action_entries,
477 G_N_ELEMENTS (msg_view_toggle_action_entries),
480 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
481 g_object_unref (action_group);
483 /* Load the UI definition */
484 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
487 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
488 g_error_free (error);
492 priv->is_search_result = FALSE;
493 priv->is_outbox = FALSE;
495 priv->msg_view = NULL;
496 priv->header_model = NULL;
497 priv->header_folder_id = NULL;
498 priv->clipboard_change_handler = 0;
499 priv->queue_change_handler = 0;
500 priv->account_removed_handler = 0;
501 priv->row_changed_handler = 0;
502 priv->row_deleted_handler = 0;
503 priv->row_inserted_handler = 0;
504 priv->rows_reordered_handler = 0;
505 priv->fetch_image_redraw_handler = 0;
506 priv->progress_hint = FALSE;
507 priv->fetching_images = 0;
509 priv->optimized_view = FALSE;
510 priv->purge_timeout = 0;
511 priv->remove_attachment_banner = NULL;
512 priv->msg_uid = NULL;
513 priv->other_body = NULL;
515 priv->sighandlers = NULL;
518 init_window (MODEST_MSG_VIEW_WINDOW(obj));
520 #ifdef MODEST_TOOLKIT_HILDON2
521 /* Grab the zoom keys, it will be used for Zoom and not for
523 g_signal_connect (G_OBJECT (obj), "realize",
524 G_CALLBACK (on_realize),
530 update_progress_hint (ModestMsgViewWindow *self)
532 ModestMsgViewWindowPrivate *priv;
533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
535 if (GTK_WIDGET_VISIBLE (self)) {
536 modest_window_show_progress (MODEST_WINDOW (self),
537 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
542 set_progress_hint (ModestMsgViewWindow *self,
545 ModestWindowPrivate *parent_priv;
546 ModestMsgViewWindowPrivate *priv;
548 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
550 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
551 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
553 /* Sets current progress hint */
554 priv->progress_hint = enabled;
556 update_progress_hint (self);
562 init_window (ModestMsgViewWindow *obj)
564 GtkWidget *main_vbox;
565 ModestMsgViewWindowPrivate *priv;
567 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
569 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
570 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
571 main_vbox = gtk_vbox_new (FALSE, 6);
573 priv->main_scroll = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
574 modest_scrollable_set_horizontal_policy (MODEST_SCROLLABLE (priv->main_scroll), GTK_POLICY_AUTOMATIC);
575 g_object_set (G_OBJECT (priv->main_scroll),
576 "movement-mode", MODEST_MOVEMENT_MODE_BOTH,
577 "horizontal-max-overshoot", 0,
579 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
580 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
581 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
583 /* NULL-ize fields if the window is destroyed */
584 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
586 gtk_widget_show_all (GTK_WIDGET(main_vbox));
590 modest_msg_view_window_disconnect_signals (ModestWindow *self)
592 ModestMsgViewWindowPrivate *priv;
593 GtkWidget *header_view = NULL;
594 GtkWindow *parent_window = NULL;
596 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
598 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
599 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
600 priv->clipboard_change_handler))
601 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
602 priv->clipboard_change_handler);
604 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
605 priv->queue_change_handler))
606 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
607 priv->queue_change_handler);
609 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
610 priv->account_removed_handler))
611 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
612 priv->account_removed_handler);
614 if (priv->header_model) {
615 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
616 priv->row_changed_handler))
617 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
618 priv->row_changed_handler);
620 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
621 priv->row_deleted_handler))
622 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
623 priv->row_deleted_handler);
625 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
626 priv->row_inserted_handler))
627 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
628 priv->row_inserted_handler);
630 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
631 priv->rows_reordered_handler))
632 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
633 priv->rows_reordered_handler);
636 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
637 priv->sighandlers = NULL;
639 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
640 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
641 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
643 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
644 MODEST_HEADER_VIEW_OBSERVER(self));
650 modest_msg_view_window_finalize (GObject *obj)
652 ModestMsgViewWindowPrivate *priv;
654 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
656 /* Sanity check: shouldn't be needed, the window mgr should
657 call this function before */
658 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
660 if (priv->fetch_image_redraw_handler > 0) {
661 g_source_remove (priv->fetch_image_redraw_handler);
662 priv->fetch_image_redraw_handler = 0;
665 if (priv->other_body != NULL) {
666 g_object_unref (priv->other_body);
667 priv->other_body = NULL;
670 if (priv->top_msg != NULL) {
671 g_object_unref (priv->top_msg);
672 priv->top_msg = NULL;
675 if (priv->header_model != NULL) {
676 g_object_unref (priv->header_model);
677 priv->header_model = NULL;
680 if (priv->remove_attachment_banner) {
681 gtk_widget_destroy (priv->remove_attachment_banner);
682 g_object_unref (priv->remove_attachment_banner);
683 priv->remove_attachment_banner = NULL;
686 if (priv->purge_timeout > 0) {
687 g_source_remove (priv->purge_timeout);
688 priv->purge_timeout = 0;
691 if (priv->row_reference) {
692 gtk_tree_row_reference_free (priv->row_reference);
693 priv->row_reference = NULL;
696 if (priv->next_row_reference) {
697 gtk_tree_row_reference_free (priv->next_row_reference);
698 priv->next_row_reference = NULL;
702 g_free (priv->msg_uid);
703 priv->msg_uid = NULL;
706 G_OBJECT_CLASS(parent_class)->finalize (obj);
710 select_next_valid_row (GtkTreeModel *model,
711 GtkTreeRowReference **row_reference,
715 GtkTreeIter tmp_iter;
717 GtkTreePath *next = NULL;
718 gboolean retval = FALSE, finished;
720 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
722 path = gtk_tree_row_reference_get_path (*row_reference);
723 gtk_tree_model_get_iter (model, &tmp_iter, path);
724 gtk_tree_row_reference_free (*row_reference);
725 *row_reference = NULL;
729 TnyHeader *header = NULL;
731 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
732 gtk_tree_model_get (model, &tmp_iter,
733 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
737 if (msg_is_visible (header, is_outbox)) {
738 next = gtk_tree_model_get_path (model, &tmp_iter);
739 *row_reference = gtk_tree_row_reference_new (model, next);
740 gtk_tree_path_free (next);
744 g_object_unref (header);
747 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
748 next = gtk_tree_model_get_path (model, &tmp_iter);
750 /* Ensure that we are not selecting the same */
751 if (gtk_tree_path_compare (path, next) != 0) {
752 gtk_tree_model_get (model, &tmp_iter,
753 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
756 if (msg_is_visible (header, is_outbox)) {
757 *row_reference = gtk_tree_row_reference_new (model, next);
761 g_object_unref (header);
765 /* If we ended up in the same message
766 then there is no valid next
770 gtk_tree_path_free (next);
772 /* If there are no more messages and we don't
773 want to start again in the first one then
774 there is no valid next message */
780 gtk_tree_path_free (path);
785 /* TODO: This should be in _init(), with the parameters as properties. */
787 modest_msg_view_window_construct (ModestMsgViewWindow *self,
788 const gchar *modest_account_name,
789 const gchar *mailbox,
790 const gchar *msg_uid)
793 ModestMsgViewWindowPrivate *priv = NULL;
794 ModestWindowPrivate *parent_priv = NULL;
795 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
796 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
798 obj = G_OBJECT (self);
799 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
800 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
802 priv->msg_uid = g_strdup (msg_uid);
805 parent_priv->menubar = NULL;
807 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
808 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
811 /* Add common dimming rules */
812 modest_dimming_rules_group_add_rules (toolbar_rules_group,
813 modest_msg_view_toolbar_dimming_entries,
814 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
815 MODEST_WINDOW (self));
816 modest_dimming_rules_group_add_rules (clipboard_rules_group,
817 modest_msg_view_clipboard_dimming_entries,
818 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
819 MODEST_WINDOW (self));
821 /* Insert dimming rules group for this window */
822 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
823 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
824 g_object_unref (toolbar_rules_group);
825 g_object_unref (clipboard_rules_group);
827 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
829 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);
830 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
831 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
832 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
833 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
834 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
835 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
836 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
837 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
838 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
839 G_CALLBACK (modest_ui_actions_on_details), obj);
840 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
841 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
842 g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
843 G_CALLBACK (modest_ui_actions_on_limit_error), obj);
844 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
845 G_CALLBACK (on_fetch_image), obj);
847 g_signal_connect (G_OBJECT (obj), "key-release-event",
848 G_CALLBACK (modest_msg_view_window_key_event),
851 g_signal_connect (G_OBJECT (obj), "key-press-event",
852 G_CALLBACK (modest_msg_view_window_key_event),
855 g_signal_connect (G_OBJECT (obj), "move-focus",
856 G_CALLBACK (on_move_focus), obj);
858 g_signal_connect (G_OBJECT (obj), "map-event",
859 G_CALLBACK (_modest_msg_view_window_map_event),
862 /* Mail Operation Queue */
863 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
865 G_CALLBACK (on_queue_changed),
868 /* Account manager */
869 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
871 G_CALLBACK(on_account_removed),
874 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
875 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
877 /* First add out toolbar ... */
878 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
880 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
882 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
883 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
884 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
885 G_CALLBACK (modest_msg_view_window_isearch_toolbar_close), obj);
886 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
887 G_CALLBACK (modest_msg_view_window_isearch_toolbar_search), obj);
888 priv->last_search = NULL;
890 /* Init the clipboard actions dim status */
891 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
893 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
898 /* FIXME: parameter checks */
900 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
901 const gchar *modest_account_name,
902 const gchar *mailbox,
903 const gchar *msg_uid,
905 GtkTreeRowReference *row_reference)
907 ModestMsgViewWindow *window = NULL;
908 ModestMsgViewWindowPrivate *priv = NULL;
909 TnyFolder *header_folder = NULL;
910 ModestHeaderView *header_view = NULL;
911 ModestWindowMgr *mgr = NULL;
914 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
917 mgr = modest_runtime_get_window_mgr ();
918 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
919 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
921 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
923 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
924 priv->top_msg = NULL;
926 /* Remember the message list's TreeModel so we can detect changes
927 * and change the list selection when necessary: */
928 header_folder = modest_header_view_get_folder (header_view);
930 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
931 TNY_FOLDER_TYPE_OUTBOX);
932 priv->header_folder_id = tny_folder_get_id (header_folder);
933 g_object_unref(header_folder);
936 /* Setup row references and connect signals */
937 priv->header_model = g_object_ref (model);
939 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
940 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
941 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
942 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
944 priv->row_reference = NULL;
945 priv->next_row_reference = NULL;
948 /* Connect signals */
949 priv->row_changed_handler =
950 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
951 G_CALLBACK(modest_msg_view_window_on_row_changed),
953 priv->row_deleted_handler =
954 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
955 G_CALLBACK(modest_msg_view_window_on_row_deleted),
957 priv->row_inserted_handler =
958 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
959 G_CALLBACK(modest_msg_view_window_on_row_inserted),
961 priv->rows_reordered_handler =
962 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
963 G_CALLBACK(modest_msg_view_window_on_row_reordered),
966 if (header_view != NULL){
967 modest_header_view_add_observer(header_view,
968 MODEST_HEADER_VIEW_OBSERVER(window));
971 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
972 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
973 update_branding (MODEST_MSG_VIEW_WINDOW (window));
975 /* gtk_widget_show_all (GTK_WIDGET (window)); */
976 modest_msg_view_window_update_priority (window);
977 /* Check dimming rules */
978 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
979 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
980 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
982 return MODEST_WINDOW(window);
986 modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
987 const gchar *mailbox,
988 const gchar *msg_uid)
990 ModestMsgViewWindow *window = NULL;
991 ModestMsgViewWindowPrivate *priv = NULL;
992 ModestWindowMgr *mgr = NULL;
994 TnyAccount *account = NULL;
996 mgr = modest_runtime_get_window_mgr ();
997 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
998 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1000 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1002 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1003 priv->top_msg = NULL;
1005 is_merge = g_str_has_prefix (msg_uid, "merge:");
1007 /* Get the account */
1009 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1012 if (is_merge || account) {
1013 TnyFolder *folder = NULL;
1015 /* Try to get the message, if it's already downloaded
1016 we don't need to connect */
1018 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
1020 ModestTnyAccountStore *account_store;
1021 ModestTnyLocalFoldersAccount *local_folders_account;
1023 account_store = modest_runtime_get_account_store ();
1024 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
1025 modest_tny_account_store_get_local_folders_account (account_store));
1026 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
1027 g_object_unref (local_folders_account);
1031 gboolean device_online;
1033 device = modest_runtime_get_device();
1034 device_online = tny_device_is_online (device);
1035 if (device_online) {
1036 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1038 TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
1040 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1041 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
1042 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1043 g_object_unref (msg);
1044 /* Sync flags to server */
1045 sync_flags (MODEST_MSG_VIEW_WINDOW (window));
1047 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1050 g_object_unref (folder);
1055 /* Check dimming rules */
1056 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1057 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1058 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1060 return MODEST_WINDOW(window);
1064 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1065 const gchar *modest_account_name,
1066 const gchar *mailbox,
1067 const gchar *msg_uid,
1068 GtkTreeRowReference *row_reference)
1070 ModestMsgViewWindow *window = NULL;
1071 ModestMsgViewWindowPrivate *priv = NULL;
1072 TnyFolder *header_folder = NULL;
1073 ModestWindowMgr *mgr = NULL;
1077 mgr = modest_runtime_get_window_mgr ();
1078 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1079 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1081 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1083 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1084 priv->top_msg = NULL;
1086 /* Remember the message list's TreeModel so we can detect changes
1087 * and change the list selection when necessary: */
1089 if (header_view != NULL){
1090 header_folder = modest_header_view_get_folder(header_view);
1091 /* This could happen if the header folder was
1092 unseleted before opening this msg window (for
1093 example if the user selects an account in the
1094 folder view of the main window */
1095 if (header_folder) {
1096 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1097 TNY_FOLDER_TYPE_OUTBOX);
1098 priv->header_folder_id = tny_folder_get_id(header_folder);
1099 g_object_unref(header_folder);
1103 /* Setup row references and connect signals */
1104 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1105 g_object_ref (priv->header_model);
1107 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
1108 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1109 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1110 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1112 priv->row_reference = NULL;
1113 priv->next_row_reference = NULL;
1116 /* Connect signals */
1117 priv->row_changed_handler =
1118 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1119 G_CALLBACK(modest_msg_view_window_on_row_changed),
1121 priv->row_deleted_handler =
1122 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1123 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1125 priv->row_inserted_handler =
1126 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1127 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1129 priv->rows_reordered_handler =
1130 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1131 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1134 if (header_view != NULL){
1135 modest_header_view_add_observer(header_view,
1136 MODEST_HEADER_VIEW_OBSERVER(window));
1139 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1140 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1142 if (priv->row_reference) {
1143 path = gtk_tree_row_reference_get_path (priv->row_reference);
1144 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1146 gtk_tree_model_get (priv->header_model, &iter,
1147 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1149 message_reader (window, priv, header, NULL, NULL, priv->row_reference);
1150 g_object_unref (header);
1152 gtk_tree_path_free (path);
1154 /* Check dimming rules */
1155 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1156 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1157 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1159 return MODEST_WINDOW(window);
1163 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1164 const gchar *modest_account_name,
1165 const gchar *mailbox,
1166 const gchar *msg_uid)
1168 ModestMsgViewWindow *window = NULL;
1169 ModestMsgViewWindowPrivate *priv = NULL;
1170 ModestWindowMgr *mgr = NULL;
1172 mgr = modest_runtime_get_window_mgr ();
1173 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1174 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1175 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1177 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1178 priv->top_msg = NULL;
1180 /* Remember that this is a search result,
1181 * so we can disable some UI appropriately: */
1182 priv->is_search_result = TRUE;
1184 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1185 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1187 update_window_title (window);
1188 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1189 modest_msg_view_window_update_priority (window);
1191 /* Check dimming rules */
1192 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1193 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1194 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1196 return MODEST_WINDOW(window);
1200 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1202 ModestMsgViewWindowPrivate *priv = NULL;
1204 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1205 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1207 return (priv->other_body != NULL);
1211 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1212 TnyMimePart *other_body,
1214 const gchar *modest_account_name,
1215 const gchar *mailbox,
1216 const gchar *msg_uid)
1218 GObject *obj = NULL;
1219 ModestMsgViewWindowPrivate *priv;
1220 ModestWindowMgr *mgr = NULL;
1222 g_return_val_if_fail (msg, NULL);
1223 mgr = modest_runtime_get_window_mgr ();
1224 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1225 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1226 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1227 modest_account_name, mailbox, msg_uid);
1230 priv->other_body = g_object_ref (other_body);
1231 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1233 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1236 priv->top_msg = g_object_ref (top_msg);
1238 priv->top_msg = NULL;
1240 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1241 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1243 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1245 /* Check dimming rules */
1246 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1247 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1248 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1250 return MODEST_WINDOW(obj);
1254 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1256 const gchar *modest_account_name,
1257 const gchar *mailbox,
1258 const gchar *msg_uid)
1260 return modest_msg_view_window_new_with_other_body (msg, NULL, top_msg, modest_account_name, mailbox, msg_uid);
1264 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1267 ModestMsgViewWindow *window)
1269 check_dimming_rules_after_change (window);
1273 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1275 ModestMsgViewWindow *window)
1277 check_dimming_rules_after_change (window);
1279 /* The window could have dissapeared */
1282 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1284 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1285 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1289 /* On insertions we check if the folder still has the message we are
1290 * showing or do not. If do not, we do nothing. Which means we are still
1291 * not attached to any header folder and thus next/prev buttons are
1292 * still dimmed. Once the message that is shown by msg-view is found, the
1293 * new model of header-view will be attached and the references will be set.
1294 * On each further insertions dimming rules will be checked. However
1295 * this requires extra CPU time at least works.
1296 * (An message might be deleted from TnyFolder and thus will not be
1297 * inserted into the model again for example if it is removed by the
1298 * imap server and the header view is refreshed.)
1301 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1302 GtkTreePath *tree_path,
1303 GtkTreeIter *tree_iter,
1304 ModestMsgViewWindow *window)
1306 ModestMsgViewWindowPrivate *priv = NULL;
1307 TnyHeader *header = NULL;
1309 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1310 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1312 g_assert (model == priv->header_model);
1314 /* Check if the newly inserted message is the same we are actually
1315 * showing. IF not, we should remain detached from the header model
1316 * and thus prev and next toolbar buttons should remain dimmed. */
1317 gtk_tree_model_get (model, tree_iter,
1318 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1321 if (TNY_IS_HEADER (header)) {
1324 uid = modest_tny_folder_get_header_unique_id (header);
1325 if (!g_str_equal(priv->msg_uid, uid)) {
1326 check_dimming_rules_after_change (window);
1328 g_object_unref (G_OBJECT(header));
1332 g_object_unref(G_OBJECT(header));
1335 if (priv->row_reference) {
1336 gtk_tree_row_reference_free (priv->row_reference);
1339 /* Setup row_reference for the actual msg. */
1340 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1341 if (priv->row_reference == NULL) {
1342 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1346 /* Now set up next_row_reference. */
1347 if (priv->next_row_reference) {
1348 gtk_tree_row_reference_free (priv->next_row_reference);
1351 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1352 select_next_valid_row (priv->header_model,
1353 &(priv->next_row_reference), FALSE, priv->is_outbox);
1355 /* Connect the remaining callbacks to become able to detect
1356 * changes in header-view. */
1357 priv->row_changed_handler =
1358 g_signal_connect (priv->header_model, "row-changed",
1359 G_CALLBACK (modest_msg_view_window_on_row_changed),
1361 priv->row_deleted_handler =
1362 g_signal_connect (priv->header_model, "row-deleted",
1363 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1365 priv->rows_reordered_handler =
1366 g_signal_connect (priv->header_model, "rows-reordered",
1367 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1370 check_dimming_rules_after_change (window);
1374 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1378 ModestMsgViewWindow *window)
1380 ModestMsgViewWindowPrivate *priv = NULL;
1381 gboolean already_changed = FALSE;
1383 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1385 /* If the current row was reordered select the proper next
1386 valid row. The same if the next row reference changes */
1387 if (!priv->row_reference ||
1388 !gtk_tree_row_reference_valid (priv->row_reference))
1391 if (priv->next_row_reference &&
1392 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1393 GtkTreePath *cur, *next;
1394 /* Check that the order is still the correct one */
1395 cur = gtk_tree_row_reference_get_path (priv->row_reference);
1396 next = gtk_tree_row_reference_get_path (priv->next_row_reference);
1397 gtk_tree_path_next (cur);
1398 if (gtk_tree_path_compare (cur, next) != 0) {
1399 gtk_tree_row_reference_free (priv->next_row_reference);
1400 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1401 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1402 already_changed = TRUE;
1404 gtk_tree_path_free (cur);
1405 gtk_tree_path_free (next);
1407 if (priv->next_row_reference)
1408 gtk_tree_row_reference_free (priv->next_row_reference);
1409 /* Update next row reference */
1410 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1411 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1412 already_changed = TRUE;
1415 check_dimming_rules_after_change (window);
1418 /* The modest_msg_view_window_update_model_replaced implements update
1419 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1420 * actually belongs to the header-view is the same as the TnyFolder of
1421 * the message of msg-view or not. If they are different, there is
1422 * nothing to do. If they are the same, then the model has replaced and
1423 * the reference in msg-view shall be replaced from the old model to
1424 * the new model. In this case the view will be detached from it's
1425 * header folder. From this point the next/prev buttons are dimmed.
1428 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1429 GtkTreeModel *model,
1430 const gchar *tny_folder_id)
1432 ModestMsgViewWindowPrivate *priv = NULL;
1433 ModestMsgViewWindow *window = NULL;
1435 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1436 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1438 window = MODEST_MSG_VIEW_WINDOW(observer);
1439 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1441 /* If there is an other folder in the header-view then we do
1442 * not care about it's model (msg list). Else if the
1443 * header-view shows the folder the msg shown by us is in, we
1444 * shall replace our model reference and make some check. */
1445 if(model == NULL || tny_folder_id == NULL ||
1446 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1449 /* Model is changed(replaced), so we should forget the old
1450 * one. Because there might be other references and there
1451 * might be some change on the model even if we unreferenced
1452 * it, we need to disconnect our signals here. */
1453 if (priv->header_model) {
1454 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1455 priv->row_changed_handler))
1456 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1457 priv->row_changed_handler);
1458 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1459 priv->row_deleted_handler))
1460 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1461 priv->row_deleted_handler);
1462 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1463 priv->row_inserted_handler))
1464 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1465 priv->row_inserted_handler);
1466 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1467 priv->rows_reordered_handler))
1468 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1469 priv->rows_reordered_handler);
1472 if (priv->row_reference)
1473 gtk_tree_row_reference_free (priv->row_reference);
1474 if (priv->next_row_reference)
1475 gtk_tree_row_reference_free (priv->next_row_reference);
1476 g_object_unref(priv->header_model);
1479 priv->row_changed_handler = 0;
1480 priv->row_deleted_handler = 0;
1481 priv->row_inserted_handler = 0;
1482 priv->rows_reordered_handler = 0;
1483 priv->next_row_reference = NULL;
1484 priv->row_reference = NULL;
1485 priv->header_model = NULL;
1488 priv->header_model = g_object_ref (model);
1490 /* Also we must connect to the new model for row insertions.
1491 * Only for insertions now. We will need other ones only after
1492 * the msg is show by msg-view is added to the new model. */
1493 priv->row_inserted_handler =
1494 g_signal_connect (priv->header_model, "row-inserted",
1495 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1498 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1499 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1503 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1505 ModestMsgViewWindowPrivate *priv= NULL;
1507 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1508 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1510 return priv->progress_hint;
1514 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1516 ModestMsgViewWindowPrivate *priv= NULL;
1518 TnyHeader *header = NULL;
1519 GtkTreePath *path = NULL;
1522 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1523 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1525 /* If the message was not obtained from a treemodel,
1526 * for instance if it was opened directly by the search UI:
1528 if (priv->header_model == NULL ||
1529 priv->row_reference == NULL ||
1530 !gtk_tree_row_reference_valid (priv->row_reference)) {
1531 msg = modest_msg_view_window_get_message (self);
1533 header = tny_msg_get_header (msg);
1534 g_object_unref (msg);
1539 /* Get iter of the currently selected message in the header view: */
1540 path = gtk_tree_row_reference_get_path (priv->row_reference);
1541 g_return_val_if_fail (path != NULL, NULL);
1542 gtk_tree_model_get_iter (priv->header_model,
1546 /* Get current message header */
1547 gtk_tree_model_get (priv->header_model, &iter,
1548 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1551 gtk_tree_path_free (path);
1556 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1558 ModestMsgViewWindowPrivate *priv;
1560 g_return_val_if_fail (self, NULL);
1562 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1564 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1568 modest_msg_view_window_get_top_message (ModestMsgViewWindow *self)
1570 ModestMsgViewWindowPrivate *priv;
1572 g_return_val_if_fail (self, NULL);
1574 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1577 return g_object_ref (priv->top_msg);
1583 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1585 ModestMsgViewWindowPrivate *priv;
1587 g_return_val_if_fail (self, NULL);
1589 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1591 return (const gchar*) priv->msg_uid;
1594 /* Used for the Ctrl+F accelerator */
1596 modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
1599 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1600 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1602 if (GTK_WIDGET_VISIBLE (priv->isearch_toolbar)) {
1603 modest_msg_view_window_isearch_toolbar_close (obj, data);
1605 modest_msg_view_window_show_isearch_toolbar (obj, data);
1609 /* Handler for menu option */
1611 modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj,
1614 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1615 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1617 gtk_widget_show (priv->isearch_toolbar);
1618 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1621 /* Handler for click on the "X" close button in isearch toolbar */
1623 modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
1624 ModestMsgViewWindow *obj)
1626 ModestMsgViewWindowPrivate *priv;
1628 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1631 gtk_widget_hide (priv->isearch_toolbar);
1632 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1636 modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
1637 ModestMsgViewWindow *obj)
1639 const gchar *current_search;
1640 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1642 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1643 modest_platform_system_banner (NULL, NULL, _("mail_ib_nothing_to_find"));
1647 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
1649 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1650 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
1654 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1656 g_free (priv->last_search);
1657 priv->last_search = g_strdup (current_search);
1658 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1661 modest_platform_system_banner (NULL, NULL,
1662 _HL_IB_FIND_NO_MATCHES);
1663 g_free (priv->last_search);
1664 priv->last_search = NULL;
1666 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1669 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1670 modest_platform_system_banner (NULL, NULL,
1671 _HL_IB_FIND_COMPLETE);
1672 g_free (priv->last_search);
1673 priv->last_search = NULL;
1675 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1682 modest_msg_view_window_set_zoom (ModestWindow *window,
1685 ModestMsgViewWindowPrivate *priv;
1686 ModestWindowPrivate *parent_priv;
1688 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1690 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1691 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1692 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1697 modest_msg_view_window_get_zoom (ModestWindow *window)
1699 ModestMsgViewWindowPrivate *priv;
1701 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1703 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1704 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1708 modest_msg_view_window_zoom_plus (ModestWindow *window)
1711 ModestMsgViewWindowPrivate *priv;
1715 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1716 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1718 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1720 if (zoom_level >= 2.0) {
1721 modest_platform_system_banner (NULL, NULL,
1722 _CS_MAX_ZOOM_LEVEL_REACHED);
1724 } else if (zoom_level >= 1.5) {
1726 } else if (zoom_level >= 1.2) {
1728 } else if (zoom_level >= 1.0) {
1730 } else if (zoom_level >= 0.8) {
1732 } else if (zoom_level >= 0.5) {
1738 /* set zoom level */
1739 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1740 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1741 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1742 g_free (banner_text);
1743 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1749 modest_msg_view_window_zoom_minus (ModestWindow *window)
1752 ModestMsgViewWindowPrivate *priv;
1756 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1757 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1759 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1761 if (zoom_level <= 0.5) {
1762 modest_platform_system_banner (NULL, NULL,
1763 _CS_MIN_ZOOM_LEVEL_REACHED);
1765 } else if (zoom_level <= 0.8) {
1767 } else if (zoom_level <= 1.0) {
1769 } else if (zoom_level <= 1.2) {
1771 } else if (zoom_level <= 1.5) {
1773 } else if (zoom_level <= 2.0) {
1779 /* set zoom level */
1780 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1781 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1782 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1783 g_free (banner_text);
1784 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1790 modest_msg_view_window_key_event (GtkWidget *window,
1796 focus = gtk_container_get_focus_child ((GtkContainer *) window);
1798 /* for the isearch toolbar case */
1799 if (focus && GTK_IS_ENTRY (focus)) {
1800 if (event->keyval == GDK_BackSpace) {
1802 copy = gdk_event_copy ((GdkEvent *) event);
1803 gtk_widget_event (focus, copy);
1804 gdk_event_free (copy);
1814 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1817 ModestMsgViewWindowPrivate *priv;
1818 GtkTreeIter tmp_iter;
1819 gboolean is_last_selected;
1821 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1822 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1824 /*if no model (so no rows at all), then virtually we are the last*/
1825 if (!priv->header_model || !priv->row_reference)
1828 if (!gtk_tree_row_reference_valid (priv->row_reference))
1831 path = gtk_tree_row_reference_get_path (priv->row_reference);
1835 is_last_selected = TRUE;
1836 while (is_last_selected) {
1838 gtk_tree_path_next (path);
1839 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1841 gtk_tree_model_get (priv->header_model, &tmp_iter,
1842 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1845 if (msg_is_visible (header, priv->is_outbox))
1846 is_last_selected = FALSE;
1847 g_object_unref(G_OBJECT(header));
1850 gtk_tree_path_free (path);
1851 return is_last_selected;
1855 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1857 ModestMsgViewWindowPrivate *priv;
1859 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1860 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1862 return priv->header_model != NULL;
1866 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1868 ModestMsgViewWindowPrivate *priv;
1870 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1871 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1873 return priv->is_search_result;
1877 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1879 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1881 if (!check_outbox) {
1884 ModestTnySendQueueStatus status;
1885 status = modest_tny_all_send_queues_get_msg_status (header);
1886 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1887 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1892 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1895 ModestMsgViewWindowPrivate *priv;
1896 gboolean is_first_selected;
1897 GtkTreeIter tmp_iter;
1899 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1900 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1902 /*if no model (so no rows at all), then virtually we are the first*/
1903 if (!priv->header_model || !priv->row_reference)
1906 if (!gtk_tree_row_reference_valid (priv->row_reference))
1909 path = gtk_tree_row_reference_get_path (priv->row_reference);
1913 is_first_selected = TRUE;
1914 while (is_first_selected) {
1916 if(!gtk_tree_path_prev (path))
1918 /* Here the 'if' is needless for logic, but let make sure
1919 * iter is valid for gtk_tree_model_get. */
1920 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1922 gtk_tree_model_get (priv->header_model, &tmp_iter,
1923 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1926 if (msg_is_visible (header, priv->is_outbox))
1927 is_first_selected = FALSE;
1928 g_object_unref(G_OBJECT(header));
1931 gtk_tree_path_free (path);
1932 return is_first_selected;
1939 GtkTreeRowReference *row_reference;
1943 message_reader_performer (gboolean canceled,
1945 ModestWindow *parent_window,
1946 TnyAccount *account,
1949 ModestMailOperation *mail_op = NULL;
1950 MsgReaderInfo *info;
1952 info = (MsgReaderInfo *) user_data;
1953 if (canceled || err) {
1954 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1955 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (parent_window));
1959 /* Register the header - it'll be unregistered in the callback */
1961 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1963 /* New mail operation */
1964 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1965 modest_ui_actions_disk_operations_error_handler,
1968 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1970 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1972 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1973 g_object_unref (mail_op);
1975 /* Update dimming rules */
1976 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1977 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1980 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1981 g_free (info->msg_uid);
1983 g_object_unref (info->folder);
1985 g_object_unref (info->header);
1986 g_slice_free (MsgReaderInfo, info);
1991 * Reads the message whose summary item is @header. It takes care of
1992 * several things, among others:
1994 * If the message was not previously downloaded then ask the user
1995 * before downloading. If there is no connection launch the connection
1996 * dialog. Update toolbar dimming rules.
1998 * Returns: TRUE if the mail operation was started, otherwise if the
1999 * user do not want to download the message, or if the user do not
2000 * want to connect, then the operation is not issued
2003 message_reader (ModestMsgViewWindow *window,
2004 ModestMsgViewWindowPrivate *priv,
2006 const gchar *msg_uid,
2008 GtkTreeRowReference *row_reference)
2010 ModestWindowMgr *mgr;
2011 TnyAccount *account = NULL;
2012 MsgReaderInfo *info;
2014 /* We set the header from model while we're loading */
2015 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
2016 modest_window_set_title (MODEST_WINDOW (window), _CS_UPDATING);
2022 g_object_ref (folder);
2024 mgr = modest_runtime_get_window_mgr ();
2025 /* Msg download completed */
2026 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
2028 /* Ask the user if he wants to download the message if
2030 if (!tny_device_is_online (modest_runtime_get_device())) {
2031 GtkResponseType response;
2032 GtkWindow *toplevel;
2034 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
2035 response = modest_platform_run_confirmation_dialog (toplevel, _("mcen_nc_get_msg"));
2036 if (response == GTK_RESPONSE_CANCEL) {
2037 update_window_title (window);
2042 folder = tny_header_get_folder (header);
2044 info = g_slice_new (MsgReaderInfo);
2045 info->msg_uid = g_strdup (msg_uid);
2047 info->header = g_object_ref (header);
2049 info->header = NULL;
2051 info->folder = g_object_ref (folder);
2053 info->folder = NULL;
2054 if (row_reference) {
2055 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2057 info->row_reference = NULL;
2060 /* Offer the connection dialog if necessary */
2061 modest_platform_connect_if_remote_and_perform ((ModestWindow *) window,
2063 TNY_FOLDER_STORE (folder),
2064 message_reader_performer,
2067 g_object_unref (folder);
2073 folder = tny_header_get_folder (header);
2076 account = tny_folder_get_account (folder);
2078 info = g_slice_new (MsgReaderInfo);
2079 info->msg_uid = g_strdup (msg_uid);
2081 info->folder = g_object_ref (folder);
2083 info->folder = NULL;
2085 info->header = g_object_ref (header);
2087 info->header = NULL;
2089 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2091 info->row_reference = NULL;
2093 message_reader_performer (FALSE, NULL, (ModestWindow *) window, account, info);
2095 g_object_unref (account);
2097 g_object_unref (folder);
2103 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2105 ModestMsgViewWindowPrivate *priv;
2106 GtkTreePath *path= NULL;
2107 GtkTreeIter tmp_iter;
2109 gboolean retval = TRUE;
2110 GtkTreeRowReference *row_reference = NULL;
2112 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2113 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2115 if (!priv->row_reference)
2118 /* Update the next row reference if it's not valid. This could
2119 happen if for example the header which it was pointing to,
2120 was deleted. The best place to do it is in the row-deleted
2121 handler but the tinymail model do not work like the glib
2122 tree models and reports the deletion when the row is still
2124 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2125 if (priv->next_row_reference) {
2126 gtk_tree_row_reference_free (priv->next_row_reference);
2128 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2129 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2130 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2132 priv->next_row_reference = NULL;
2135 if (priv->next_row_reference)
2136 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2140 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2142 gtk_tree_model_get_iter (priv->header_model,
2145 gtk_tree_path_free (path);
2147 gtk_tree_model_get (priv->header_model, &tmp_iter,
2148 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2151 /* Read the message & show it */
2152 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2155 gtk_tree_row_reference_free (row_reference);
2158 g_object_unref (header);
2164 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2166 ModestMsgViewWindowPrivate *priv = NULL;
2168 gboolean finished = FALSE;
2169 gboolean retval = FALSE;
2171 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2172 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2174 if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
2175 gtk_tree_row_reference_free (priv->row_reference);
2176 priv->row_reference = NULL;
2179 /* Return inmediatly if there is no header model */
2180 if (!priv->header_model || !priv->row_reference)
2183 path = gtk_tree_row_reference_get_path (priv->row_reference);
2184 while (!finished && gtk_tree_path_prev (path)) {
2188 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2189 gtk_tree_model_get (priv->header_model, &iter,
2190 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2194 if (msg_is_visible (header, priv->is_outbox)) {
2195 GtkTreeRowReference *row_reference;
2196 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2197 /* Read the message & show it */
2198 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2199 gtk_tree_row_reference_free (row_reference);
2203 g_object_unref (header);
2207 gtk_tree_path_free (path);
2212 view_msg_cb (ModestMailOperation *mail_op,
2219 ModestMsgViewWindow *self = NULL;
2220 ModestMsgViewWindowPrivate *priv = NULL;
2221 GtkTreeRowReference *row_reference = NULL;
2223 /* Unregister the header (it was registered before creating the mail operation) */
2224 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2226 row_reference = (GtkTreeRowReference *) user_data;
2229 gtk_tree_row_reference_free (row_reference);
2230 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2232 /* Restore window title */
2233 update_window_title (self);
2234 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2235 g_object_unref (self);
2240 /* If there was any error */
2241 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2243 gtk_tree_row_reference_free (row_reference);
2244 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2246 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2247 /* First we check if the parent is a folder window */
2248 if (priv->msg_uid && !modest_window_mgr_get_folder_window (MODEST_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2250 TnyAccount *account = NULL;
2251 GtkWidget *header_window = NULL;
2253 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2255 /* Get the account */
2257 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2260 if (is_merge || account) {
2261 TnyFolder *folder = NULL;
2263 /* Try to get the message, if it's already downloaded
2264 we don't need to connect */
2266 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2269 ModestTnyAccountStore *account_store;
2270 ModestTnyLocalFoldersAccount *local_folders_account;
2272 account_store = modest_runtime_get_account_store ();
2273 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2274 modest_tny_account_store_get_local_folders_account (account_store));
2275 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2276 g_object_unref (local_folders_account);
2278 if (account) g_object_unref (account);
2281 header_window = (GtkWidget *)
2282 modest_header_window_new (
2284 modest_window_get_active_account (MODEST_WINDOW (self)),
2285 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2286 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2287 MODEST_WINDOW (header_window),
2289 gtk_widget_destroy (GTK_WIDGET (header_window));
2291 gtk_widget_show_all (GTK_WIDGET (header_window));
2293 g_object_unref (folder);
2299 /* Restore window title */
2300 update_window_title (self);
2301 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2302 g_object_unref (self);
2307 /* Get the window */
2308 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2309 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2310 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2312 /* Update the row reference */
2313 if (priv->row_reference != NULL) {
2314 gtk_tree_row_reference_free (priv->row_reference);
2315 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2316 if (priv->next_row_reference != NULL) {
2317 gtk_tree_row_reference_free (priv->next_row_reference);
2319 if (priv->row_reference) {
2320 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2321 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2323 priv->next_row_reference = NULL;
2327 /* Mark header as read */
2328 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2329 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2331 /* Set new message */
2332 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2333 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2334 modest_msg_view_window_update_priority (self);
2335 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2336 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2337 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2340 /* Set the new message uid of the window */
2341 if (priv->msg_uid) {
2342 g_free (priv->msg_uid);
2343 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2346 /* Notify the observers */
2347 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2348 0, priv->header_model, priv->row_reference);
2350 /* Sync the flags if the message is not opened from a header
2351 model, i.e, if it's opened from a notification */
2352 if (!priv->header_model)
2356 g_object_unref (self);
2358 gtk_tree_row_reference_free (row_reference);
2362 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2364 ModestMsgViewWindowPrivate *priv;
2366 TnyFolderType folder_type;
2368 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2370 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2372 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2376 folder = tny_msg_get_folder (msg);
2378 folder_type = modest_tny_folder_guess_folder_type (folder);
2379 g_object_unref (folder);
2381 g_object_unref (msg);
2389 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2391 ModestMsgViewWindowPrivate *priv;
2392 TnyHeader *header = NULL;
2393 TnyHeaderFlags flags = 0;
2395 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2397 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2399 GtkTreePath *path = NULL;
2401 path = gtk_tree_row_reference_get_path (priv->row_reference);
2402 g_return_if_fail (path != NULL);
2403 gtk_tree_model_get_iter (priv->header_model,
2405 gtk_tree_row_reference_get_path (priv->row_reference));
2407 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2409 gtk_tree_path_free (path);
2412 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2414 header = tny_msg_get_header (msg);
2415 g_object_unref (msg);
2420 flags = tny_header_get_flags (header);
2421 g_object_unref(G_OBJECT(header));
2424 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2429 toolbar_resize (ModestMsgViewWindow *self)
2431 ModestMsgViewWindowPrivate *priv = NULL;
2432 ModestWindowPrivate *parent_priv = NULL;
2434 gint static_button_size;
2435 ModestWindowMgr *mgr;
2437 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2438 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2439 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2441 mgr = modest_runtime_get_window_mgr ();
2442 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2444 if (parent_priv->toolbar) {
2445 /* Set expandable and homogeneous tool buttons */
2446 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2447 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2448 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2449 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2450 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2451 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2452 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2453 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2454 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2455 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2456 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2457 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2458 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2459 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2460 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2461 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2462 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2463 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2464 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2469 modest_msg_view_window_show_toolbar (ModestWindow *self,
2470 gboolean show_toolbar)
2472 ModestMsgViewWindowPrivate *priv = NULL;
2473 ModestWindowPrivate *parent_priv;
2475 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2476 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2478 /* Set optimized view status */
2479 priv->optimized_view = !show_toolbar;
2481 if (!parent_priv->toolbar) {
2482 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2485 #ifdef MODEST_TOOLKIT_HILDON2
2486 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2488 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), GTK_ICON_SIZE_LARGE_TOOLBAR);
2490 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2492 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2493 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2494 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2496 modest_window_add_toolbar (MODEST_WINDOW (self),
2497 GTK_TOOLBAR (parent_priv->toolbar));
2502 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2503 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2504 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2506 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2507 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2508 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2510 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2513 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2514 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2519 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2521 ModestMsgViewWindow *window)
2523 if (!GTK_WIDGET_VISIBLE (window))
2526 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2530 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2532 ModestMsgViewWindowPrivate *priv;
2534 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2535 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2537 return priv->progress_hint;
2541 observers_empty (ModestMsgViewWindow *self)
2544 ModestMsgViewWindowPrivate *priv;
2545 gboolean is_empty = TRUE;
2546 guint pending_ops = 0;
2548 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2549 tmp = priv->progress_widgets;
2551 /* Check all observers */
2552 while (tmp && is_empty) {
2553 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2554 is_empty = pending_ops == 0;
2556 tmp = g_slist_next(tmp);
2563 on_account_removed (TnyAccountStore *account_store,
2564 TnyAccount *account,
2567 /* Do nothing if it's a transport account, because we only
2568 show the messages of a store account */
2569 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2570 const gchar *parent_acc = NULL;
2571 const gchar *our_acc = NULL;
2573 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2574 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2576 /* Close this window if I'm showing a message of the removed account */
2577 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2578 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2583 on_mail_operation_started (ModestMailOperation *mail_op,
2586 ModestMsgViewWindow *self;
2587 ModestMailOperationTypeOperation op_type;
2589 ModestMsgViewWindowPrivate *priv;
2590 GObject *source = NULL;
2592 self = MODEST_MSG_VIEW_WINDOW (user_data);
2593 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2594 op_type = modest_mail_operation_get_type_operation (mail_op);
2595 tmp = priv->progress_widgets;
2596 source = modest_mail_operation_get_source(mail_op);
2597 if (G_OBJECT (self) == source) {
2598 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2599 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2600 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2601 set_progress_hint (self, TRUE);
2603 modest_progress_object_add_operation (
2604 MODEST_PROGRESS_OBJECT (tmp->data),
2606 tmp = g_slist_next (tmp);
2610 g_object_unref (source);
2612 /* Update dimming rules */
2613 check_dimming_rules_after_change (self);
2617 on_mail_operation_finished (ModestMailOperation *mail_op,
2620 ModestMsgViewWindow *self;
2621 ModestMailOperationTypeOperation op_type;
2623 ModestMsgViewWindowPrivate *priv;
2625 self = MODEST_MSG_VIEW_WINDOW (user_data);
2626 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2627 op_type = modest_mail_operation_get_type_operation (mail_op);
2628 tmp = priv->progress_widgets;
2630 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2631 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2632 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2634 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2636 tmp = g_slist_next (tmp);
2639 /* If no more operations are being observed, NORMAL mode is enabled again */
2640 if (observers_empty (self)) {
2641 set_progress_hint (self, FALSE);
2645 /* Update dimming rules. We have to do this right here
2646 and not in view_msg_cb because at that point the
2647 transfer mode is still enabled so the dimming rule
2648 won't let the user delete the message that has been
2649 readed for example */
2650 check_dimming_rules_after_change (self);
2654 on_queue_changed (ModestMailOperationQueue *queue,
2655 ModestMailOperation *mail_op,
2656 ModestMailOperationQueueNotification type,
2657 ModestMsgViewWindow *self)
2659 ModestMsgViewWindowPrivate *priv;
2661 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2663 /* If this operations was created by another window, do nothing */
2664 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2667 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2668 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2670 "operation-started",
2671 G_CALLBACK (on_mail_operation_started),
2673 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2675 "operation-finished",
2676 G_CALLBACK (on_mail_operation_finished),
2678 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2679 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2681 "operation-started");
2682 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2684 "operation-finished");
2689 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2691 ModestMsgViewWindowPrivate *priv;
2692 TnyList *selected_attachments = NULL;
2694 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2695 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2697 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2698 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2700 return selected_attachments;
2704 ModestMsgViewWindow *self;
2706 gchar *attachment_uid;
2707 } DecodeAsyncHelper;
2710 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2716 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2717 const gchar *content_type;
2718 ModestMsgViewWindowPrivate *priv;
2720 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2722 if (cancelled || err) {
2725 if ((err->domain == TNY_ERROR_DOMAIN) &&
2726 (err->code == TNY_IO_ERROR_WRITE) &&
2727 (errno == ENOSPC)) {
2728 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2730 msg = g_strdup (_("mail_ib_file_operation_failed"));
2732 modest_platform_information_banner (NULL, NULL, msg);
2738 /* It could happen that the window was closed. So we
2739 assume it is a cancelation */
2740 if (!GTK_WIDGET_VISIBLE (helper->self))
2743 /* Remove the progress hint */
2744 set_progress_hint (helper->self, FALSE);
2746 content_type = tny_mime_part_get_content_type (mime_part);
2747 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2748 ModestWindowMgr *mgr;
2749 ModestWindow *msg_win = NULL;
2752 const gchar *mailbox;
2753 TnyStream *file_stream;
2756 fd = g_open (helper->file_path, O_RDONLY, 0644);
2759 file_stream = tny_fs_stream_new (fd);
2761 mgr = modest_runtime_get_window_mgr ();
2763 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2764 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2767 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2769 msg = tny_camel_msg_new ();
2770 tny_camel_msg_parse (TNY_CAMEL_MSG (msg), file_stream);
2773 top_msg = g_object_ref (priv->top_msg);
2775 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2777 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2778 account, mailbox, helper->attachment_uid);
2779 if (top_msg) g_object_unref (top_msg);
2780 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2781 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2782 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2783 gtk_widget_show_all (GTK_WIDGET (msg_win));
2785 gtk_widget_destroy (GTK_WIDGET (msg_win));
2786 g_object_unref (msg);
2787 g_object_unref (file_stream);
2789 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2794 /* make the file read-only */
2795 g_chmod(helper->file_path, 0444);
2797 /* Activate the file */
2798 modest_platform_activate_file (helper->file_path, content_type);
2803 g_object_unref (helper->self);
2804 g_free (helper->file_path);
2805 g_free (helper->attachment_uid);
2806 g_slice_free (DecodeAsyncHelper, helper);
2810 view_attachment_connect_handler (gboolean canceled,
2812 GtkWindow *parent_window,
2813 TnyAccount *account,
2817 if (canceled || err) {
2818 g_object_unref (part);
2822 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2824 g_object_unref (part);
2828 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2829 TnyMimePart *mime_part)
2831 ModestMsgViewWindowPrivate *priv;
2832 const gchar *msg_uid;
2833 gchar *attachment_uid = NULL;
2834 gint attachment_index = 0;
2835 TnyList *attachments;
2837 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2838 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2839 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2841 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2842 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2843 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2844 g_object_unref (attachments);
2846 if (msg_uid && attachment_index >= 0) {
2847 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2850 if (mime_part == NULL) {
2851 gboolean error = FALSE;
2852 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2853 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2855 } else if (tny_list_get_length (selected_attachments) > 1) {
2856 modest_platform_system_banner (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2860 iter = tny_list_create_iterator (selected_attachments);
2861 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2862 g_object_unref (iter);
2864 if (selected_attachments)
2865 g_object_unref (selected_attachments);
2870 g_object_ref (mime_part);
2873 if (tny_mime_part_is_purged (mime_part))
2876 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2877 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2879 TnyAccount *account;
2881 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2883 /* Get the account */
2885 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2888 if (!tny_device_is_online (modest_runtime_get_device())) {
2889 modest_platform_connect_and_perform ((ModestWindow *) window,
2891 TNY_ACCOUNT (account),
2892 (ModestConnectedPerformer) view_attachment_connect_handler,
2893 g_object_ref (mime_part));
2898 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2899 gchar *filepath = NULL;
2900 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2901 gboolean show_error_banner = FALSE;
2902 TnyFsStream *temp_stream = NULL;
2903 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2906 if (temp_stream != NULL) {
2907 ModestAccountMgr *mgr;
2908 DecodeAsyncHelper *helper;
2909 gboolean decode_in_provider;
2910 ModestProtocol *protocol;
2911 const gchar *account;
2913 /* Activate progress hint */
2914 set_progress_hint (window, TRUE);
2916 helper = g_slice_new0 (DecodeAsyncHelper);
2917 helper->self = g_object_ref (window);
2918 helper->file_path = g_strdup (filepath);
2919 helper->attachment_uid = g_strdup (attachment_uid);
2921 decode_in_provider = FALSE;
2922 mgr = modest_runtime_get_account_mgr ();
2923 account = modest_window_get_active_account (MODEST_WINDOW (window));
2924 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2925 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2927 uri = g_strconcat ("file://", filepath, NULL);
2928 decode_in_provider =
2929 modest_account_protocol_decode_part_to_stream_async (
2930 MODEST_ACCOUNT_PROTOCOL (protocol),
2933 TNY_STREAM (temp_stream),
2934 on_decode_to_stream_async_handler,
2941 if (!decode_in_provider)
2942 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2943 on_decode_to_stream_async_handler,
2946 g_object_unref (temp_stream);
2947 /* NOTE: files in the temporary area will be automatically
2948 * cleaned after some time if they are no longer in use */
2951 const gchar *content_type;
2952 /* the file may already exist but it isn't writable,
2953 * let's try to open it anyway */
2954 content_type = tny_mime_part_get_content_type (mime_part);
2955 modest_platform_activate_file (filepath, content_type);
2957 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2958 show_error_banner = TRUE;
2963 if (show_error_banner)
2964 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2965 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2966 ModestWindowMgr *mgr;
2967 ModestWindow *msg_win = NULL;
2968 TnyMsg *current_msg;
2972 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2973 mgr = modest_runtime_get_window_mgr ();
2974 header = tny_msg_get_header (TNY_MSG (current_msg));
2975 found = modest_window_mgr_find_registered_message_uid (mgr,
2980 g_debug ("window for this body is already being created");
2984 /* it's not found, so create a new window for it */
2985 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2986 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2987 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2989 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2992 top_msg = g_object_ref (priv->top_msg);
2994 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2996 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
2997 account, mailbox, attachment_uid);
2999 if (top_msg) g_object_unref (top_msg);
3001 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3002 modest_window_get_zoom (MODEST_WINDOW (window)));
3003 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3004 gtk_widget_show_all (GTK_WIDGET (msg_win));
3006 gtk_widget_destroy (GTK_WIDGET (msg_win));
3008 g_object_unref (current_msg);
3010 /* message attachment */
3011 TnyHeader *header = NULL;
3012 ModestWindowMgr *mgr;
3013 ModestWindow *msg_win = NULL;
3016 header = tny_msg_get_header (TNY_MSG (mime_part));
3017 mgr = modest_runtime_get_window_mgr ();
3018 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3021 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3022 * thus, we don't do anything */
3023 g_debug ("window for is already being created");
3026 /* it's not found, so create a new window for it */
3027 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3028 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3029 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3031 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3033 top_msg = g_object_ref (priv->top_msg);
3035 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3036 msg_win = modest_msg_view_window_new_for_attachment (
3037 TNY_MSG (mime_part), top_msg, account,
3038 mailbox, attachment_uid);
3039 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3040 modest_window_get_zoom (MODEST_WINDOW (window)));
3041 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3042 gtk_widget_show_all (GTK_WIDGET (msg_win));
3044 gtk_widget_destroy (GTK_WIDGET (msg_win));
3050 g_free (attachment_uid);
3052 g_object_unref (mime_part);
3064 GnomeVFSResult result;
3066 ModestMsgViewWindow *window;
3069 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3070 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3071 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3072 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3075 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3079 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3080 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3081 g_free (pair->filename);
3082 g_object_unref (pair->part);
3083 g_slice_free (SaveMimePartPair, pair);
3085 g_list_free (info->pairs);
3088 g_object_unref (info->window);
3089 info->window = NULL;
3091 g_slice_free (SaveMimePartInfo, info);
3096 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3098 /* This is a GDK lock because we are an idle callback and
3099 * modest_platform_system_banner is or does Gtk+ code */
3101 gdk_threads_enter (); /* CHECKED */
3102 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3104 } else if (info->result == GNOME_VFS_OK) {
3105 modest_platform_system_banner (NULL, NULL, _CS_SAVED);
3106 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3109 /* Check if the uri belongs to the external mmc */
3110 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3111 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3113 msg = g_strdup (_KR("cerm_memory_card_full"));
3114 modest_platform_information_banner (NULL, NULL, msg);
3117 modest_platform_system_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
3119 save_mime_part_info_free (info, FALSE);
3120 gdk_threads_leave (); /* CHECKED */
3126 save_mime_part_to_file_connect_handler (gboolean canceled,
3128 GtkWindow *parent_window,
3129 TnyAccount *account,
3130 SaveMimePartInfo *info)
3132 if (canceled || err) {
3133 if (canceled && !err) {
3134 info->result = GNOME_VFS_ERROR_CANCELLED;
3136 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3138 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3143 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3146 TnyAccount *account;
3147 ModestMsgViewWindowPrivate *priv;
3149 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3151 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3154 /* Get the account */
3156 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3159 modest_platform_connect_and_perform ((ModestWindow *) info->window,
3161 TNY_ACCOUNT (account),
3162 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3166 g_object_unref (account);
3172 save_mime_part_to_file (SaveMimePartInfo *info)
3174 GnomeVFSHandle *handle;
3176 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3178 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3179 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3180 gboolean check_online = TRUE;
3181 ModestMsgViewWindowPrivate *priv = NULL;
3183 /* Check if we really need to connect to save the mime part */
3184 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3185 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3186 check_online = FALSE;
3188 TnyAccountStore *acc_store;
3189 TnyAccount *account = NULL;
3191 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3192 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3195 if (tny_account_get_connection_status (account) ==
3196 TNY_CONNECTION_STATUS_CONNECTED)
3197 check_online = FALSE;
3198 g_object_unref (account);
3200 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3205 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3210 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3211 if (info->result == GNOME_VFS_OK) {
3212 GError *error = NULL;
3213 gboolean decode_in_provider;
3215 ModestAccountMgr *mgr;
3216 const gchar *account;
3217 ModestProtocol *protocol = NULL;
3219 stream = tny_vfs_stream_new (handle);
3221 decode_in_provider = FALSE;
3222 mgr = modest_runtime_get_account_mgr ();
3223 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3224 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3225 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3226 decode_in_provider =
3227 modest_account_protocol_decode_part_to_stream (
3228 MODEST_ACCOUNT_PROTOCOL (protocol),
3236 if (!decode_in_provider)
3237 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3240 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3242 if ((error->domain == TNY_ERROR_DOMAIN) &&
3243 (error->code == TNY_IO_ERROR_WRITE) &&
3244 (errno == ENOSPC)) {
3245 info->result = GNOME_VFS_ERROR_NO_SPACE;
3247 info->result = GNOME_VFS_ERROR_IO;
3250 g_object_unref (G_OBJECT (stream));
3252 g_warning ("Could not create save attachment %s: %s\n",
3253 pair->filename, gnome_vfs_result_to_string (info->result));
3256 /* Go on saving remaining files */
3257 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3258 if (info->pairs != NULL) {
3259 save_mime_part_to_file (info);
3261 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3268 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3269 SaveMimePartInfo *info)
3271 gboolean is_ok = TRUE;
3272 gint replaced_files = 0;
3273 const GList *files = info->pairs;
3274 const GList *iter, *to_replace = NULL;
3276 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3277 SaveMimePartPair *pair = iter->data;
3278 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3280 if (modest_utils_file_exists (unescaped)) {
3282 if (replaced_files == 1)
3287 if (replaced_files) {
3290 if (replaced_files == 1) {
3291 SaveMimePartPair *pair = to_replace->data;
3292 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3293 gchar *escaped_basename, *message;
3295 escaped_basename = g_uri_unescape_string (basename, NULL);
3296 message = g_strdup_printf ("%s\n%s",
3298 (escaped_basename) ? escaped_basename : "");
3299 response = modest_platform_run_confirmation_dialog (parent, message);
3301 g_free (escaped_basename);
3303 response = modest_platform_run_confirmation_dialog (parent,
3304 _FM_REPLACE_MULTIPLE);
3306 if (response != GTK_RESPONSE_OK)
3311 save_mime_part_info_free (info, TRUE);
3313 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3318 typedef struct _SaveAttachmentsInfo {
3319 TnyList *attachments_list;
3320 ModestMsgViewWindow *window;
3321 } SaveAttachmentsInfo;
3324 save_attachments_response (GtkDialog *dialog,
3328 TnyList *mime_parts;
3330 GList *files_to_save = NULL;
3331 gchar *current_folder;
3332 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3334 mime_parts = TNY_LIST (sa_info->attachments_list);
3336 if (arg1 != GTK_RESPONSE_OK)
3339 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3340 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3341 if (current_folder && *current_folder != '\0') {
3343 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3344 current_folder,&err);
3346 g_debug ("Error storing latest used folder: %s", err->message);
3350 g_free (current_folder);
3352 if (!modest_utils_folder_writable (chooser_uri)) {
3353 const gchar *err_msg;
3355 #ifdef MODEST_PLATFORM_MAEMO
3356 if (modest_maemo_utils_in_usb_mode ()) {
3357 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3359 err_msg = _FM_READ_ONLY_LOCATION;
3362 err_msg = _FM_READ_ONLY_LOCATION;
3364 modest_platform_system_banner (NULL, NULL, err_msg);
3368 iter = tny_list_create_iterator (mime_parts);
3369 while (!tny_iterator_is_done (iter)) {
3370 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3372 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3373 !tny_mime_part_is_purged (mime_part) &&
3374 (tny_mime_part_get_filename (mime_part) != NULL)) {
3375 SaveMimePartPair *pair;
3377 pair = g_slice_new0 (SaveMimePartPair);
3379 if (tny_list_get_length (mime_parts) > 1) {
3381 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3382 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3385 pair->filename = g_strdup (chooser_uri);
3387 pair->part = mime_part;
3388 files_to_save = g_list_prepend (files_to_save, pair);
3390 tny_iterator_next (iter);
3392 g_object_unref (iter);
3395 if (files_to_save != NULL) {
3396 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3397 info->pairs = files_to_save;
3398 info->result = TRUE;
3399 info->uri = g_strdup (chooser_uri);
3400 info->window = g_object_ref (sa_info->window);
3401 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3403 g_free (chooser_uri);
3406 /* Free and close the dialog */
3407 g_object_unref (mime_parts);
3408 g_object_unref (sa_info->window);
3409 g_slice_free (SaveAttachmentsInfo, sa_info);
3410 gtk_widget_destroy (GTK_WIDGET (dialog));
3414 msg_is_attachment (TnyList *mime_parts)
3417 gboolean retval = FALSE;
3419 if (tny_list_get_length (mime_parts) > 1)
3422 iter = tny_list_create_iterator (mime_parts);
3424 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3426 if (TNY_IS_MSG (part))
3428 g_object_unref (part);
3430 g_object_unref (iter);
3436 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3437 TnyList *mime_parts)
3439 ModestMsgViewWindowPrivate *priv;
3440 GtkWidget *save_dialog = NULL;
3441 gchar *conf_folder = NULL;
3442 gchar *filename = NULL;
3443 gchar *save_multiple_str = NULL;
3444 const gchar *root_folder = "file:///";
3446 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3447 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3449 if (mime_parts == NULL) {
3450 gboolean allow_msgs = FALSE;
3452 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3453 * selection available */
3454 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3456 /* Check if the message is composed by an unique MIME
3457 part whose content disposition is attachment. There
3458 could be messages like this:
3460 Date: Tue, 12 Jan 2010 20:40:59 +0000
3461 From: <sender@example.org>
3462 To: <recipient@example.org>
3464 Content-Type: image/jpeg
3465 Content-Disposition: attachment; filename="bug7718.jpeg"
3467 whose unique MIME part is the message itself whose
3468 content disposition is attachment
3470 if (mime_parts && msg_is_attachment (mime_parts))
3473 if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, allow_msgs)) {
3474 g_object_unref (mime_parts);
3478 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3480 g_object_unref (mime_parts);
3486 g_object_ref (mime_parts);
3489 /* prepare dialog */
3490 if (tny_list_get_length (mime_parts) == 1) {
3492 /* only one attachment selected */
3493 iter = tny_list_create_iterator (mime_parts);
3494 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3495 g_object_unref (iter);
3496 if (!modest_tny_mime_part_is_msg (mime_part) &&
3497 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3498 !tny_mime_part_is_purged (mime_part)) {
3499 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3501 /* TODO: show any error? */
3502 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3503 g_object_unref (mime_parts);
3506 g_object_unref (mime_part);
3508 gint num = tny_list_get_length (mime_parts);
3509 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3510 "sfil_va_number_of_objects_attachment",
3511 "sfil_va_number_of_objects_attachments",
3515 /* Creation of hildon file chooser dialog for saving */
3516 save_dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
3518 (GtkWindow *) window,
3519 GTK_FILE_CHOOSER_ACTION_SAVE);
3521 /* Get last used folder */
3522 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3523 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3525 /* File chooser stops working if we select "file:///" as current folder */
3526 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3527 g_free (conf_folder);
3531 if (conf_folder && conf_folder[0] != '\0') {
3532 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3535 /* Set the default folder to documents folder */
3536 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3539 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3541 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3542 g_free (docs_folder);
3544 g_free (conf_folder);
3548 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3553 /* if multiple, set multiple string */
3554 if (save_multiple_str) {
3555 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3556 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM_SAVE_OBJECT_FILES);
3557 g_free (save_multiple_str);
3560 /* We must run this asynchronously, because the hildon dialog
3561 performs a gtk_dialog_run by itself which leads to gdk
3563 SaveAttachmentsInfo *sa_info;
3564 sa_info = g_slice_new (SaveAttachmentsInfo);
3565 sa_info->attachments_list = mime_parts;
3566 sa_info->window = g_object_ref (window);
3567 g_signal_connect (save_dialog, "response",
3568 G_CALLBACK (save_attachments_response), sa_info);
3570 gtk_widget_show_all (save_dialog);
3574 show_remove_attachment_information (gpointer userdata)
3576 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3577 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3579 /* We're outside the main lock */
3580 gdk_threads_enter ();
3582 if (priv->remove_attachment_banner != NULL) {
3583 gtk_widget_destroy (priv->remove_attachment_banner);
3584 g_object_unref (priv->remove_attachment_banner);
3587 priv->remove_attachment_banner = g_object_ref (
3588 modest_platform_animation_banner (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3590 gdk_threads_leave ();
3596 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3598 ModestMsgViewWindowPrivate *priv;
3599 TnyList *mime_parts = NULL, *tmp;
3600 gchar *confirmation_message;
3606 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3607 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3609 #ifdef MODEST_TOOLKIT_HILDON2
3610 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3611 * because we don't have selection
3613 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3615 /* Remove already purged messages from mime parts list. We use
3616 a copy of the list to remove items in the original one */
3617 tmp = tny_list_copy (mime_parts);
3618 iter = tny_list_create_iterator (tmp);
3619 while (!tny_iterator_is_done (iter)) {
3620 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3621 if (tny_mime_part_is_purged (part))
3622 tny_list_remove (mime_parts, (GObject *) part);
3624 g_object_unref (part);
3625 tny_iterator_next (iter);
3627 g_object_unref (tmp);
3628 g_object_unref (iter);
3630 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3631 tny_list_get_length (mime_parts) == 0) {
3632 g_object_unref (mime_parts);
3636 /* In gtk we get only selected attachments for the operation.
3638 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
3640 /* Remove already purged messages from mime parts list. We use
3641 a copy of the list to remove items in the original one */
3642 tmp = tny_list_copy (mime_parts);
3643 iter = tny_list_create_iterator (tmp);
3644 while (!tny_iterator_is_done (iter)) {
3645 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3646 if (tny_mime_part_is_purged (part))
3647 tny_list_remove (mime_parts, (GObject *) part);
3649 g_object_unref (part);
3650 tny_iterator_next (iter);
3652 g_object_unref (tmp);
3653 g_object_unref (iter);
3655 if (tny_list_get_length (mime_parts) == 0) {
3656 g_object_unref (mime_parts);
3661 n_attachments = tny_list_get_length (mime_parts);
3662 if (n_attachments == 1) {
3666 iter = tny_list_create_iterator (mime_parts);
3667 part = (TnyMimePart *) tny_iterator_get_current (iter);
3668 g_object_unref (iter);
3669 if (modest_tny_mime_part_is_msg (part)) {
3671 header = tny_msg_get_header (TNY_MSG (part));
3672 filename = tny_header_dup_subject (header);
3673 g_object_unref (header);
3674 if (filename == NULL)
3675 filename = g_strdup (_("mail_va_no_subject"));
3677 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3679 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3681 g_object_unref (part);
3683 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3684 "mcen_nc_purge_files_text",
3685 n_attachments), n_attachments);
3687 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3688 confirmation_message);
3689 g_free (confirmation_message);
3691 if (response != GTK_RESPONSE_OK) {
3692 g_object_unref (mime_parts);
3696 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3698 iter = tny_list_create_iterator (mime_parts);
3699 while (!tny_iterator_is_done (iter)) {
3702 part = (TnyMimePart *) tny_iterator_get_current (iter);
3703 tny_mime_part_set_purged (TNY_MIME_PART (part));
3704 g_object_unref (part);
3705 tny_iterator_next (iter);
3707 g_object_unref (iter);
3709 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3710 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3711 tny_msg_rewrite_cache (msg);
3712 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3713 g_object_unref (msg);
3714 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3716 g_object_unref (mime_parts);
3718 if (priv->purge_timeout > 0) {
3719 g_source_remove (priv->purge_timeout);
3720 priv->purge_timeout = 0;
3723 if (priv->remove_attachment_banner) {
3724 gtk_widget_destroy (priv->remove_attachment_banner);
3725 g_object_unref (priv->remove_attachment_banner);
3726 priv->remove_attachment_banner = NULL;
3732 update_window_title (ModestMsgViewWindow *window)
3734 ModestMsgViewWindowPrivate *priv;
3736 TnyHeader *header = NULL;
3737 gchar *subject = NULL;
3739 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3741 /* Note that if the window is closed while we're retrieving
3742 the message, this widget could de deleted */
3743 if (!priv->msg_view)
3746 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3748 if (priv->other_body) {
3751 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3753 g_strstrip (description);
3754 subject = description;
3756 } else if (msg != NULL) {
3757 header = tny_msg_get_header (msg);
3758 subject = tny_header_dup_subject (header);
3759 g_object_unref (header);
3760 g_object_unref (msg);
3763 if ((subject == NULL)||(subject[0] == '\0')) {
3765 subject = g_strdup (_("mail_va_no_subject"));
3768 modest_window_set_title (MODEST_WINDOW (window), subject);
3773 on_move_focus (GtkWidget *widget,
3774 GtkDirectionType direction,
3777 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3781 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3783 GnomeVFSResult result;
3784 GnomeVFSHandle *handle = NULL;
3785 GnomeVFSFileInfo *info = NULL;
3788 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3789 if (result != GNOME_VFS_OK) {
3794 info = gnome_vfs_file_info_new ();
3795 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3796 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3797 /* We put a "safe" default size for going to cache */
3798 *expected_size = (300*1024);
3800 *expected_size = info->size;
3802 gnome_vfs_file_info_unref (info);
3804 stream = tny_vfs_stream_new (handle);
3813 TnyStream *output_stream;
3814 GtkWidget *msg_view;
3819 on_fetch_image_timeout_refresh_view (gpointer userdata)
3821 ModestMsgViewWindowPrivate *priv;
3823 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3824 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3825 /* Note that priv->msg_view is set to NULL when this window is
3827 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3828 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3830 priv->fetch_image_redraw_handler = 0;
3831 g_object_unref (userdata);
3836 on_fetch_image_idle_refresh_view (gpointer userdata)
3839 FetchImageData *fidata = (FetchImageData *) userdata;
3841 gdk_threads_enter ();
3842 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3843 ModestMsgViewWindowPrivate *priv;
3845 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3846 priv->fetching_images--;
3847 if (priv->fetch_image_redraw_handler == 0) {
3848 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3852 gdk_threads_leave ();
3854 g_object_unref (fidata->msg_view);
3855 g_object_unref (fidata->window);
3856 g_slice_free (FetchImageData, fidata);
3861 on_fetch_image_thread (gpointer userdata)
3863 FetchImageData *fidata = (FetchImageData *) userdata;
3864 TnyStreamCache *cache;
3865 TnyStream *cache_stream;
3867 cache = modest_runtime_get_images_cache ();
3869 tny_stream_cache_get_stream (cache,
3871 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3872 (gpointer) fidata->uri);
3873 g_free (fidata->cache_id);
3874 g_free (fidata->uri);
3876 if (cache_stream != NULL) {
3879 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3882 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3883 if (G_UNLIKELY (nb_read < 0)) {
3885 } else if (G_LIKELY (nb_read > 0)) {
3886 gssize nb_written = 0;
3888 while (G_UNLIKELY (nb_written < nb_read)) {
3891 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3892 nb_read - nb_written);
3893 if (G_UNLIKELY (len < 0))
3899 tny_stream_close (cache_stream);
3900 g_object_unref (cache_stream);
3903 tny_stream_close (fidata->output_stream);
3904 g_object_unref (fidata->output_stream);
3906 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3912 on_fetch_image (ModestMsgView *msgview,
3915 ModestMsgViewWindow *window)
3917 const gchar *current_account;
3918 ModestMsgViewWindowPrivate *priv;
3919 FetchImageData *fidata;
3921 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3923 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3925 fidata = g_slice_new0 (FetchImageData);
3926 fidata->msg_view = g_object_ref (msgview);
3927 fidata->window = g_object_ref (window);
3928 fidata->uri = g_strdup (uri);
3929 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3930 fidata->output_stream = g_object_ref (stream);
3932 priv->fetching_images++;
3933 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3934 g_object_unref (fidata->output_stream);
3935 g_free (fidata->cache_id);
3936 g_free (fidata->uri);
3937 g_object_unref (fidata->msg_view);
3938 g_slice_free (FetchImageData, fidata);
3939 tny_stream_close (stream);
3940 priv->fetching_images--;
3941 update_progress_hint (window);
3944 update_progress_hint (window);
3950 setup_menu (ModestMsgViewWindow *self)
3952 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3954 /* Settings menu buttons */
3955 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3956 MODEST_WINDOW_MENU_CALLBACK (modest_msg_view_window_show_isearch_toolbar),
3957 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3959 modest_window_add_to_menu (MODEST_WINDOW (self),
3960 dngettext(GETTEXT_PACKAGE,
3961 "mcen_me_move_message",
3962 "mcen_me_move_messages",
3965 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_move_to),
3966 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3968 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3969 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3970 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3972 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3973 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3974 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3976 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3977 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_save_attachments),
3978 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3979 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3980 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3981 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3983 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3984 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3985 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3986 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3987 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3988 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3990 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3991 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_details),
3992 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3996 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3998 ModestMsgViewWindowPrivate *priv;
3999 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4000 GSList *recipients = NULL;
4003 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
4007 header = modest_msg_view_window_get_header (self);
4010 recipients = modest_tny_msg_header_get_all_recipients_list (header);
4011 g_object_unref (header);
4013 recipients = modest_tny_msg_get_all_recipients_list (msg);
4014 g_object_unref (msg);
4018 /* Offer the user to add recipients to the address book */
4019 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
4020 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
4025 _modest_msg_view_window_map_event (GtkWidget *widget,
4029 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
4031 update_progress_hint (self);
4037 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4039 ModestMsgViewWindowPrivate *priv;
4040 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4042 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4046 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4048 ModestMsgViewWindowPrivate *priv;
4049 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4051 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4053 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4057 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4059 ModestMsgViewWindowPrivate *priv;
4060 const gchar *msg_uid;
4061 TnyHeader *header = NULL;
4062 TnyFolder *folder = NULL;
4064 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4066 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4068 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4072 folder = tny_header_get_folder (header);
4073 g_object_unref (header);
4078 msg_uid = modest_msg_view_window_get_message_uid (self);
4080 GtkTreeRowReference *row_reference;
4082 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4083 row_reference = priv->row_reference;
4085 row_reference = NULL;
4087 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4088 g_warning ("Shouldn't happen, trying to reload a message failed");
4091 g_object_unref (folder);
4095 update_branding (ModestMsgViewWindow *self)
4097 const gchar *account;
4098 const gchar *mailbox;
4099 ModestAccountMgr *mgr;
4100 ModestProtocol *protocol = NULL;
4101 gchar *service_name = NULL;
4102 const GdkPixbuf *service_icon = NULL;
4103 ModestMsgViewWindowPrivate *priv;
4105 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4107 account = modest_window_get_active_account (MODEST_WINDOW (self));
4108 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4110 mgr = modest_runtime_get_account_mgr ();
4112 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4113 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4114 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4116 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4117 account, mailbox, MODEST_ICON_SIZE_SMALL);
4121 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4122 g_free (service_name);
4126 sync_flags (ModestMsgViewWindow *self)
4128 TnyHeader *header = NULL;
4130 header = modest_msg_view_window_get_header (self);
4132 TnyMsg *msg = modest_msg_view_window_get_message (self);
4134 header = tny_msg_get_header (msg);
4135 g_object_unref (msg);
4140 TnyFolder *folder = tny_header_get_folder (header);
4143 ModestMailOperation *mail_op;
4145 /* Sync folder, we need this to save the seen flag */
4146 mail_op = modest_mail_operation_new (NULL);
4147 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4149 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4150 g_object_unref (mail_op);
4151 g_object_unref (folder);
4153 g_object_unref (header);
4157 #ifdef MODEST_TOOLKIT_HILDON2
4159 on_realize (GtkWidget *widget,
4162 GdkDisplay *display;
4164 unsigned long val = 1;
4166 display = gdk_drawable_get_display (widget->window);
4167 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4168 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4169 GDK_WINDOW_XID (widget->window), atom,
4170 XA_INTEGER, 32, PropModeReplace,
4171 (unsigned char *) &val, 1);