1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include <tny-error.h>
37 #include "modest-marshal.h"
38 #include "modest-platform.h"
39 #include <modest-utils.h>
40 #include <modest-toolkit-utils.h>
41 #include <modest-tny-msg.h>
42 #include <modest-msg-view-window.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-progress-object.h>
46 #include <modest-runtime.h>
47 #include <modest-window-priv.h>
48 #include <modest-tny-folder.h>
49 #include <modest-text-utils.h>
50 #include <modest-account-mgr-helpers.h>
51 #include <modest-toolkit-factory.h>
52 #include <modest-scrollable.h>
53 #include <modest-isearch-toolbar.h>
54 #include "modest-defs.h"
55 #include "modest-ui-dimming-manager.h"
56 #include <gdk/gdkkeysyms.h>
57 #include <modest-tny-account.h>
58 #include <modest-mime-part-view.h>
59 #include <modest-isearch-view.h>
60 #include <modest-tny-mime-part.h>
61 #include <modest-address-book.h>
64 #include <glib/gstdio.h>
65 #include <modest-debug.h>
66 #include <modest-header-window.h>
67 #include <modest-account-protocol.h>
68 #include <modest-icon-names.h>
69 #include <modest-ui-actions.h>
70 #include <modest-window-mgr.h>
71 #include <tny-camel-msg.h>
72 #include <modest-icon-names.h>
74 #ifdef MODEST_PLATFORM_MAEMO
75 #include <modest-maemo-utils.h>
78 #ifdef MODEST_TOOLKIT_HILDON2
79 #include <hildon/hildon.h>
81 #include <X11/Xatom.h>
82 #include <X11/XKBlib.h>
83 #include <X11/Xdmcp.h>
86 #include <tny-camel-bs-mime-part.h>
87 #include <tny-camel-bs-msg.h>
89 #define MYDOCS_ENV "MYDOCSDIR"
90 #define DOCS_FOLDER ".documents"
92 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
93 struct _ModestMsgViewWindowPrivate {
96 GtkWidget *main_scroll;
97 GtkWidget *isearch_toolbar;
100 /* Progress observers */
101 GSList *progress_widgets;
104 GtkWidget *prev_toolitem;
105 GtkWidget *next_toolitem;
106 gboolean progress_hint;
107 gint fetching_images;
109 /* Optimized view enabled */
110 gboolean optimized_view;
112 /* Whether this was created via the *_new_for_search_result() function. */
113 gboolean is_search_result;
115 /* Whether the message is in outbox */
118 /* A reference to the @model of the header view
119 * to allow selecting previous/next messages,
120 * if the message is currently selected in the header view.
122 const gchar *header_folder_id;
123 GtkTreeModel *header_model;
124 GtkTreeRowReference *row_reference;
125 GtkTreeRowReference *next_row_reference;
127 gulong clipboard_change_handler;
128 gulong queue_change_handler;
129 gulong account_removed_handler;
130 gulong row_changed_handler;
131 gulong row_deleted_handler;
132 gulong row_inserted_handler;
133 gulong rows_reordered_handler;
134 gulong fetch_image_redraw_handler;
137 GtkWidget *remove_attachment_banner;
140 TnyMimePart *other_body;
146 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
147 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
148 static void modest_header_view_observer_init (ModestHeaderViewObserverIface *iface_class);
149 static void modest_msg_view_window_finalize (GObject *obj);
150 static void modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj, gpointer data);
151 static void modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
152 ModestMsgViewWindow *obj);
153 static void modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
154 ModestMsgViewWindow *obj);
155 static void modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
157 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
159 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
160 static void modest_msg_view_window_set_zoom (ModestWindow *window,
162 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
163 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
164 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
167 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
169 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
170 gboolean show_toolbar);
172 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
174 ModestMsgViewWindow *window);
176 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
179 ModestMsgViewWindow *window);
181 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
183 ModestMsgViewWindow *window);
185 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
186 GtkTreePath *tree_path,
187 GtkTreeIter *tree_iter,
188 ModestMsgViewWindow *window);
190 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
194 ModestMsgViewWindow *window);
196 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
198 const gchar *tny_folder_id);
200 static void on_queue_changed (ModestMailOperationQueue *queue,
201 ModestMailOperation *mail_op,
202 ModestMailOperationQueueNotification type,
203 ModestMsgViewWindow *self);
205 static void on_account_removed (TnyAccountStore *account_store,
209 static void on_move_focus (GtkWidget *widget,
210 GtkDirectionType direction,
213 static void view_msg_cb (ModestMailOperation *mail_op,
220 static void set_progress_hint (ModestMsgViewWindow *self,
223 static void update_window_title (ModestMsgViewWindow *window);
225 static void init_window (ModestMsgViewWindow *obj);
227 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
229 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
231 static gboolean on_fetch_image (ModestMsgView *msgview,
234 ModestMsgViewWindow *window);
236 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
237 GtkScrollType scroll_type,
240 static gboolean message_reader (ModestMsgViewWindow *window,
241 ModestMsgViewWindowPrivate *priv,
243 const gchar *msg_uid,
245 GtkTreeRowReference *row_reference);
247 static void setup_menu (ModestMsgViewWindow *self);
248 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
251 static void update_branding (ModestMsgViewWindow *self);
252 static void sync_flags (ModestMsgViewWindow *self);
253 static gboolean on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part,
254 GtkContainer *container, ModestMsgViewWindow *self);
256 static gboolean on_realize (GtkWidget *widget,
259 /* list my signals */
266 static const GtkActionEntry msg_view_toolbar_action_entries [] = {
269 { "ToolbarMessageReply", MODEST_STOCK_REPLY, N_("mcen_me_inbox_reply"), "<CTRL>R", NULL, G_CALLBACK (modest_ui_actions_on_reply) },
270 { "ToolbarMessageReplyAll", MODEST_STOCK_REPLY_ALL, N_("mcen_me_inbox_replytoall"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
271 { "ToolbarMessageForward", MODEST_STOCK_FORWARD, N_("mcen_me_inbox_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_forward) },
272 { "ToolbarDeleteMessage", MODEST_STOCK_DELETE, N_("qgn_toolb_gene_deletebutton"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_message_or_folder) },
273 { "ToolbarMessageBack", MODEST_TOOLBAR_ICON_PREV, N_("qgn_toolb_gene_back"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_prev) },
274 { "ToolbarMessageNext", MODEST_TOOLBAR_ICON_NEXT, N_("qgn_toolb_gene_forward"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_next) },
275 { "ToolbarDownloadExternalImages", MODEST_TOOLBAR_ICON_DOWNLOAD_IMAGES, N_("mail_bd_external_images"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_fetch_images) },
278 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
279 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_isearch_toolbar), FALSE },
282 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
283 MODEST_TYPE_MSG_VIEW_WINDOW, \
284 ModestMsgViewWindowPrivate))
286 static GtkWindowClass *parent_class = NULL;
288 /* uncomment the following if you have defined any signals */
289 static guint signals[LAST_SIGNAL] = {0};
292 modest_msg_view_window_get_type (void)
294 static GType my_type = 0;
296 static const GTypeInfo my_info = {
297 sizeof(ModestMsgViewWindowClass),
298 NULL, /* base init */
299 NULL, /* base finalize */
300 (GClassInitFunc) modest_msg_view_window_class_init,
301 NULL, /* class finalize */
302 NULL, /* class data */
303 sizeof(ModestMsgViewWindow),
305 (GInstanceInitFunc) modest_msg_view_window_init,
308 #ifndef MODEST_TOOLKIT_HILDON2
309 my_type = g_type_register_static (MODEST_TYPE_SHELL_WINDOW,
310 "ModestMsgViewWindow",
313 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
314 "ModestMsgViewWindow",
318 static const GInterfaceInfo modest_header_view_observer_info =
320 (GInterfaceInitFunc) modest_header_view_observer_init,
321 NULL, /* interface_finalize */
322 NULL /* interface_data */
325 g_type_add_interface_static (my_type,
326 MODEST_TYPE_HEADER_VIEW_OBSERVER,
327 &modest_header_view_observer_info);
333 save_state (ModestWindow *self)
335 modest_widget_memory_save (modest_runtime_get_conf (),
337 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
341 modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
342 GtkScrollType scroll_type,
346 ModestMsgViewWindowPrivate *priv;
349 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
351 switch (scroll_type) {
352 case GTK_SCROLL_STEP_UP:
355 case GTK_SCROLL_STEP_DOWN:
358 case GTK_SCROLL_PAGE_UP:
361 case GTK_SCROLL_PAGE_DOWN:
364 case GTK_SCROLL_START:
375 modest_scrollable_scroll ((ModestScrollable *) priv->main_scroll, 0, step);
377 return (gboolean) step;
381 add_scroll_binding (GtkBindingSet *binding_set,
383 GtkScrollType scroll)
385 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
387 gtk_binding_entry_add_signal (binding_set, keyval, 0,
389 GTK_TYPE_SCROLL_TYPE, scroll,
390 G_TYPE_BOOLEAN, FALSE);
391 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
393 GTK_TYPE_SCROLL_TYPE, scroll,
394 G_TYPE_BOOLEAN, FALSE);
398 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
400 GObjectClass *gobject_class;
401 ModestWindowClass *modest_window_class;
402 GtkBindingSet *binding_set;
404 gobject_class = (GObjectClass*) klass;
405 modest_window_class = (ModestWindowClass *) klass;
407 parent_class = g_type_class_peek_parent (klass);
408 gobject_class->finalize = modest_msg_view_window_finalize;
410 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
411 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
412 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
413 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
414 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
415 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
417 modest_window_class->save_state_func = save_state;
419 klass->scroll_child = modest_msg_view_window_scroll_child;
421 signals[MSG_CHANGED_SIGNAL] =
422 g_signal_new ("msg-changed",
423 G_TYPE_FROM_CLASS (gobject_class),
425 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
427 modest_marshal_VOID__POINTER_POINTER,
428 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
430 signals[SCROLL_CHILD_SIGNAL] =
431 g_signal_new ("scroll-child",
432 G_TYPE_FROM_CLASS (gobject_class),
433 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
434 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
436 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
437 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
439 binding_set = gtk_binding_set_by_class (klass);
440 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
441 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
442 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
443 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
444 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
445 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
447 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
451 static void modest_header_view_observer_init(
452 ModestHeaderViewObserverIface *iface_class)
454 iface_class->update_func = modest_msg_view_window_update_model_replaced;
458 modest_msg_view_window_init (ModestMsgViewWindow *obj)
460 ModestMsgViewWindowPrivate *priv;
461 ModestWindowPrivate *parent_priv = NULL;
462 GtkActionGroup *action_group = NULL;
463 GError *error = NULL;
465 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
466 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
467 parent_priv->ui_manager = gtk_ui_manager_new();
469 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
470 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
472 /* Add common actions */
473 gtk_action_group_add_actions (action_group,
474 msg_view_toolbar_action_entries,
475 G_N_ELEMENTS (msg_view_toolbar_action_entries),
477 gtk_action_group_add_toggle_actions (action_group,
478 msg_view_toggle_action_entries,
479 G_N_ELEMENTS (msg_view_toggle_action_entries),
482 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
483 g_object_unref (action_group);
485 /* Load the UI definition */
486 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
489 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
490 g_error_free (error);
494 priv->is_search_result = FALSE;
495 priv->is_outbox = FALSE;
497 priv->msg_view = NULL;
498 priv->header_model = NULL;
499 priv->header_folder_id = NULL;
500 priv->clipboard_change_handler = 0;
501 priv->queue_change_handler = 0;
502 priv->account_removed_handler = 0;
503 priv->row_changed_handler = 0;
504 priv->row_deleted_handler = 0;
505 priv->row_inserted_handler = 0;
506 priv->rows_reordered_handler = 0;
507 priv->fetch_image_redraw_handler = 0;
508 priv->progress_hint = FALSE;
509 priv->fetching_images = 0;
511 priv->optimized_view = FALSE;
512 priv->purge_timeout = 0;
513 priv->remove_attachment_banner = NULL;
514 priv->msg_uid = NULL;
515 priv->other_body = NULL;
517 priv->sighandlers = NULL;
520 init_window (MODEST_MSG_VIEW_WINDOW(obj));
522 #ifdef MODEST_TOOLKIT_HILDON2
523 /* Grab the zoom keys, it will be used for Zoom and not for
525 g_signal_connect (G_OBJECT (obj), "realize",
526 G_CALLBACK (on_realize),
532 update_progress_hint (ModestMsgViewWindow *self)
534 ModestMsgViewWindowPrivate *priv;
535 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
537 if (GTK_WIDGET_VISIBLE (self)) {
538 modest_window_show_progress (MODEST_WINDOW (self),
539 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
544 set_progress_hint (ModestMsgViewWindow *self,
547 ModestWindowPrivate *parent_priv;
548 ModestMsgViewWindowPrivate *priv;
550 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
552 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
553 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
555 /* Sets current progress hint */
556 priv->progress_hint = enabled;
558 update_progress_hint (self);
564 init_window (ModestMsgViewWindow *obj)
566 GtkWidget *main_vbox;
567 ModestMsgViewWindowPrivate *priv;
569 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
571 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
572 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
573 main_vbox = gtk_vbox_new (FALSE, 6);
575 priv->main_scroll = modest_toolkit_factory_create_scrollable (modest_runtime_get_toolkit_factory ());
576 modest_scrollable_set_horizontal_policy (MODEST_SCROLLABLE (priv->main_scroll), GTK_POLICY_AUTOMATIC);
577 g_object_set (G_OBJECT (priv->main_scroll),
578 "movement-mode", MODEST_MOVEMENT_MODE_BOTH,
579 "horizontal-max-overshoot", 0,
581 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
582 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
583 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
585 /* NULL-ize fields if the window is destroyed */
586 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
588 gtk_widget_show_all (GTK_WIDGET(main_vbox));
592 modest_msg_view_window_disconnect_signals (ModestWindow *self)
594 ModestMsgViewWindowPrivate *priv;
595 GtkWidget *header_view = NULL;
596 GtkWindow *parent_window = NULL;
598 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
600 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
601 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
602 priv->clipboard_change_handler))
603 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
604 priv->clipboard_change_handler);
606 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
607 priv->queue_change_handler))
608 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
609 priv->queue_change_handler);
611 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
612 priv->account_removed_handler))
613 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
614 priv->account_removed_handler);
616 if (priv->header_model) {
617 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
618 priv->row_changed_handler))
619 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
620 priv->row_changed_handler);
622 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
623 priv->row_deleted_handler))
624 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
625 priv->row_deleted_handler);
627 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
628 priv->row_inserted_handler))
629 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
630 priv->row_inserted_handler);
632 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
633 priv->rows_reordered_handler))
634 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
635 priv->rows_reordered_handler);
638 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
639 priv->sighandlers = NULL;
641 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
642 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
643 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
645 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
646 MODEST_HEADER_VIEW_OBSERVER(self));
652 modest_msg_view_window_finalize (GObject *obj)
654 ModestMsgViewWindowPrivate *priv;
656 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
658 /* Sanity check: shouldn't be needed, the window mgr should
659 call this function before */
660 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
662 if (priv->fetch_image_redraw_handler > 0) {
663 g_source_remove (priv->fetch_image_redraw_handler);
664 priv->fetch_image_redraw_handler = 0;
667 if (priv->other_body != NULL) {
668 g_object_unref (priv->other_body);
669 priv->other_body = NULL;
672 if (priv->top_msg != NULL) {
673 g_object_unref (priv->top_msg);
674 priv->top_msg = NULL;
677 if (priv->header_model != NULL) {
678 g_object_unref (priv->header_model);
679 priv->header_model = NULL;
682 if (priv->remove_attachment_banner) {
683 gtk_widget_destroy (priv->remove_attachment_banner);
684 g_object_unref (priv->remove_attachment_banner);
685 priv->remove_attachment_banner = NULL;
688 if (priv->purge_timeout > 0) {
689 g_source_remove (priv->purge_timeout);
690 priv->purge_timeout = 0;
693 if (priv->row_reference) {
694 gtk_tree_row_reference_free (priv->row_reference);
695 priv->row_reference = NULL;
698 if (priv->next_row_reference) {
699 gtk_tree_row_reference_free (priv->next_row_reference);
700 priv->next_row_reference = NULL;
704 g_free (priv->msg_uid);
705 priv->msg_uid = NULL;
708 G_OBJECT_CLASS(parent_class)->finalize (obj);
712 select_next_valid_row (GtkTreeModel *model,
713 GtkTreeRowReference **row_reference,
717 GtkTreeIter tmp_iter;
719 GtkTreePath *next = NULL;
720 gboolean retval = FALSE, finished;
722 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
724 path = gtk_tree_row_reference_get_path (*row_reference);
725 gtk_tree_model_get_iter (model, &tmp_iter, path);
726 gtk_tree_row_reference_free (*row_reference);
727 *row_reference = NULL;
731 TnyHeader *header = NULL;
733 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
734 gtk_tree_model_get (model, &tmp_iter,
735 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
739 if (msg_is_visible (header, is_outbox)) {
740 next = gtk_tree_model_get_path (model, &tmp_iter);
741 *row_reference = gtk_tree_row_reference_new (model, next);
742 gtk_tree_path_free (next);
746 g_object_unref (header);
749 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
750 next = gtk_tree_model_get_path (model, &tmp_iter);
752 /* Ensure that we are not selecting the same */
753 if (gtk_tree_path_compare (path, next) != 0) {
754 gtk_tree_model_get (model, &tmp_iter,
755 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
758 if (msg_is_visible (header, is_outbox)) {
759 *row_reference = gtk_tree_row_reference_new (model, next);
763 g_object_unref (header);
767 /* If we ended up in the same message
768 then there is no valid next
772 gtk_tree_path_free (next);
774 /* If there are no more messages and we don't
775 want to start again in the first one then
776 there is no valid next message */
782 gtk_tree_path_free (path);
787 /* TODO: This should be in _init(), with the parameters as properties. */
789 modest_msg_view_window_construct (ModestMsgViewWindow *self,
790 const gchar *modest_account_name,
791 const gchar *mailbox,
792 const gchar *msg_uid)
795 ModestMsgViewWindowPrivate *priv = NULL;
796 ModestWindowPrivate *parent_priv = NULL;
797 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
798 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
800 obj = G_OBJECT (self);
801 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
802 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
804 priv->msg_uid = g_strdup (msg_uid);
807 parent_priv->menubar = NULL;
809 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
810 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
813 /* Add common dimming rules */
814 modest_dimming_rules_group_add_rules (toolbar_rules_group,
815 modest_msg_view_toolbar_dimming_entries,
816 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
817 MODEST_WINDOW (self));
818 modest_dimming_rules_group_add_rules (clipboard_rules_group,
819 modest_msg_view_clipboard_dimming_entries,
820 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
821 MODEST_WINDOW (self));
823 /* Insert dimming rules group for this window */
824 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
825 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
826 g_object_unref (toolbar_rules_group);
827 g_object_unref (clipboard_rules_group);
829 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
831 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
832 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
833 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
834 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
835 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
836 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
837 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
838 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
839 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
840 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
841 G_CALLBACK (modest_ui_actions_on_details), obj);
842 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
843 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
844 g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
845 G_CALLBACK (modest_ui_actions_on_limit_error), obj);
846 g_signal_connect (G_OBJECT(priv->msg_view), "handle_calendar",
847 G_CALLBACK (on_handle_calendar), obj);
848 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
849 G_CALLBACK (on_fetch_image), obj);
851 g_signal_connect (G_OBJECT (obj), "key-release-event",
852 G_CALLBACK (modest_msg_view_window_key_event),
855 g_signal_connect (G_OBJECT (obj), "key-press-event",
856 G_CALLBACK (modest_msg_view_window_key_event),
859 g_signal_connect (G_OBJECT (obj), "move-focus",
860 G_CALLBACK (on_move_focus), obj);
862 g_signal_connect (G_OBJECT (obj), "map-event",
863 G_CALLBACK (_modest_msg_view_window_map_event),
866 /* Mail Operation Queue */
867 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
869 G_CALLBACK (on_queue_changed),
872 /* Account manager */
873 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
875 G_CALLBACK(on_account_removed),
878 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
879 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
881 /* First add out toolbar ... */
882 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
884 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
886 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
887 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
888 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
889 G_CALLBACK (modest_msg_view_window_isearch_toolbar_close), obj);
890 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
891 G_CALLBACK (modest_msg_view_window_isearch_toolbar_search), obj);
892 priv->last_search = NULL;
894 /* Init the clipboard actions dim status */
895 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
897 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
902 /* FIXME: parameter checks */
904 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
905 const gchar *modest_account_name,
906 const gchar *mailbox,
907 const gchar *msg_uid,
909 GtkTreeRowReference *row_reference)
911 ModestMsgViewWindow *window = NULL;
912 ModestMsgViewWindowPrivate *priv = NULL;
913 TnyFolder *header_folder = NULL;
914 ModestHeaderView *header_view = NULL;
915 ModestWindowMgr *mgr = NULL;
918 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
921 mgr = modest_runtime_get_window_mgr ();
922 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
923 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
925 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
927 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
928 priv->top_msg = NULL;
930 /* Remember the message list's TreeModel so we can detect changes
931 * and change the list selection when necessary: */
932 header_folder = modest_header_view_get_folder (header_view);
934 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
935 TNY_FOLDER_TYPE_OUTBOX);
936 priv->header_folder_id = tny_folder_get_id (header_folder);
937 g_object_unref(header_folder);
940 /* Setup row references and connect signals */
941 priv->header_model = g_object_ref (model);
943 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
944 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
945 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
946 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
948 priv->row_reference = NULL;
949 priv->next_row_reference = NULL;
952 /* Connect signals */
953 priv->row_changed_handler =
954 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
955 G_CALLBACK(modest_msg_view_window_on_row_changed),
957 priv->row_deleted_handler =
958 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
959 G_CALLBACK(modest_msg_view_window_on_row_deleted),
961 priv->row_inserted_handler =
962 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
963 G_CALLBACK(modest_msg_view_window_on_row_inserted),
965 priv->rows_reordered_handler =
966 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
967 G_CALLBACK(modest_msg_view_window_on_row_reordered),
970 if (header_view != NULL){
971 modest_header_view_add_observer(header_view,
972 MODEST_HEADER_VIEW_OBSERVER(window));
975 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
976 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
977 update_branding (MODEST_MSG_VIEW_WINDOW (window));
979 /* gtk_widget_show_all (GTK_WIDGET (window)); */
980 modest_msg_view_window_update_priority (window);
981 /* Check dimming rules */
982 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
983 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
984 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
986 return MODEST_WINDOW(window);
990 modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
991 const gchar *mailbox,
992 const gchar *msg_uid)
994 ModestMsgViewWindow *window = NULL;
995 ModestMsgViewWindowPrivate *priv = NULL;
996 ModestWindowMgr *mgr = NULL;
998 TnyAccount *account = NULL;
1000 mgr = modest_runtime_get_window_mgr ();
1001 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1002 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1004 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1006 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1007 priv->top_msg = NULL;
1009 is_merge = g_str_has_prefix (msg_uid, "merge:");
1011 /* Get the account */
1013 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1016 if (is_merge || account) {
1017 TnyFolder *folder = NULL;
1019 /* Try to get the message, if it's already downloaded
1020 we don't need to connect */
1022 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
1024 ModestTnyAccountStore *account_store;
1025 ModestTnyLocalFoldersAccount *local_folders_account;
1027 account_store = modest_runtime_get_account_store ();
1028 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
1029 modest_tny_account_store_get_local_folders_account (account_store));
1030 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
1031 g_object_unref (local_folders_account);
1035 gboolean device_online;
1037 device = modest_runtime_get_device();
1038 device_online = tny_device_is_online (device);
1039 if (device_online) {
1040 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1042 TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
1044 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1045 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
1046 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1047 g_object_unref (msg);
1048 /* Sync flags to server */
1049 sync_flags (MODEST_MSG_VIEW_WINDOW (window));
1051 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1054 g_object_unref (folder);
1059 /* Check dimming rules */
1060 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1061 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1062 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1064 return MODEST_WINDOW(window);
1068 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1069 const gchar *modest_account_name,
1070 const gchar *mailbox,
1071 const gchar *msg_uid,
1072 GtkTreeRowReference *row_reference)
1074 ModestMsgViewWindow *window = NULL;
1075 ModestMsgViewWindowPrivate *priv = NULL;
1076 TnyFolder *header_folder = NULL;
1077 ModestWindowMgr *mgr = NULL;
1081 mgr = modest_runtime_get_window_mgr ();
1082 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1083 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1085 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1087 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1088 priv->top_msg = NULL;
1090 /* Remember the message list's TreeModel so we can detect changes
1091 * and change the list selection when necessary: */
1093 if (header_view != NULL){
1094 header_folder = modest_header_view_get_folder(header_view);
1095 /* This could happen if the header folder was
1096 unseleted before opening this msg window (for
1097 example if the user selects an account in the
1098 folder view of the main window */
1099 if (header_folder) {
1100 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1101 TNY_FOLDER_TYPE_OUTBOX);
1102 priv->header_folder_id = tny_folder_get_id(header_folder);
1103 g_object_unref(header_folder);
1107 /* Setup row references and connect signals */
1108 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1109 g_object_ref (priv->header_model);
1111 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
1112 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1113 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1114 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1116 priv->row_reference = NULL;
1117 priv->next_row_reference = NULL;
1120 /* Connect signals */
1121 priv->row_changed_handler =
1122 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1123 G_CALLBACK(modest_msg_view_window_on_row_changed),
1125 priv->row_deleted_handler =
1126 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1127 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1129 priv->row_inserted_handler =
1130 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1131 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1133 priv->rows_reordered_handler =
1134 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1135 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1138 if (header_view != NULL){
1139 modest_header_view_add_observer(header_view,
1140 MODEST_HEADER_VIEW_OBSERVER(window));
1143 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1144 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1146 if (priv->row_reference) {
1147 path = gtk_tree_row_reference_get_path (priv->row_reference);
1148 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1150 gtk_tree_model_get (priv->header_model, &iter,
1151 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1153 message_reader (window, priv, header, NULL, NULL, priv->row_reference);
1154 g_object_unref (header);
1156 gtk_tree_path_free (path);
1158 /* Check dimming rules */
1159 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1160 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1161 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1163 return MODEST_WINDOW(window);
1167 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1168 const gchar *modest_account_name,
1169 const gchar *mailbox,
1170 const gchar *msg_uid)
1172 ModestMsgViewWindow *window = NULL;
1173 ModestMsgViewWindowPrivate *priv = NULL;
1174 ModestWindowMgr *mgr = NULL;
1176 mgr = modest_runtime_get_window_mgr ();
1177 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1178 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1179 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1181 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1182 priv->top_msg = NULL;
1184 /* Remember that this is a search result,
1185 * so we can disable some UI appropriately: */
1186 priv->is_search_result = TRUE;
1188 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1189 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1191 update_window_title (window);
1192 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1193 modest_msg_view_window_update_priority (window);
1195 /* Check dimming rules */
1196 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1197 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1198 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1200 return MODEST_WINDOW(window);
1204 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1206 ModestMsgViewWindowPrivate *priv = NULL;
1208 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1209 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1211 return (priv->other_body != NULL);
1215 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1216 TnyMimePart *other_body,
1218 const gchar *modest_account_name,
1219 const gchar *mailbox,
1220 const gchar *msg_uid)
1222 GObject *obj = NULL;
1223 ModestMsgViewWindowPrivate *priv;
1224 ModestWindowMgr *mgr = NULL;
1226 g_return_val_if_fail (msg, NULL);
1227 mgr = modest_runtime_get_window_mgr ();
1228 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1229 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1230 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1231 modest_account_name, mailbox, msg_uid);
1234 priv->other_body = g_object_ref (other_body);
1235 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1237 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1240 priv->top_msg = g_object_ref (top_msg);
1242 priv->top_msg = NULL;
1244 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1245 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1247 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1249 /* Check dimming rules */
1250 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1251 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1252 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1254 return MODEST_WINDOW(obj);
1258 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1260 const gchar *modest_account_name,
1261 const gchar *mailbox,
1262 const gchar *msg_uid)
1264 return modest_msg_view_window_new_with_other_body (msg, NULL, top_msg, modest_account_name, mailbox, msg_uid);
1268 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1271 ModestMsgViewWindow *window)
1273 check_dimming_rules_after_change (window);
1277 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1279 ModestMsgViewWindow *window)
1281 check_dimming_rules_after_change (window);
1283 /* The window could have dissapeared */
1286 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1288 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1289 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1293 /* On insertions we check if the folder still has the message we are
1294 * showing or do not. If do not, we do nothing. Which means we are still
1295 * not attached to any header folder and thus next/prev buttons are
1296 * still dimmed. Once the message that is shown by msg-view is found, the
1297 * new model of header-view will be attached and the references will be set.
1298 * On each further insertions dimming rules will be checked. However
1299 * this requires extra CPU time at least works.
1300 * (An message might be deleted from TnyFolder and thus will not be
1301 * inserted into the model again for example if it is removed by the
1302 * imap server and the header view is refreshed.)
1305 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1306 GtkTreePath *tree_path,
1307 GtkTreeIter *tree_iter,
1308 ModestMsgViewWindow *window)
1310 ModestMsgViewWindowPrivate *priv = NULL;
1311 TnyHeader *header = NULL;
1313 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1314 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1316 g_assert (model == priv->header_model);
1318 /* Check if the newly inserted message is the same we are actually
1319 * showing. IF not, we should remain detached from the header model
1320 * and thus prev and next toolbar buttons should remain dimmed. */
1321 gtk_tree_model_get (model, tree_iter,
1322 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1325 if (TNY_IS_HEADER (header)) {
1328 uid = modest_tny_folder_get_header_unique_id (header);
1329 if (!g_str_equal(priv->msg_uid, uid)) {
1330 check_dimming_rules_after_change (window);
1332 g_object_unref (G_OBJECT(header));
1336 g_object_unref(G_OBJECT(header));
1339 if (priv->row_reference) {
1340 gtk_tree_row_reference_free (priv->row_reference);
1343 /* Setup row_reference for the actual msg. */
1344 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1345 if (priv->row_reference == NULL) {
1346 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1350 /* Now set up next_row_reference. */
1351 if (priv->next_row_reference) {
1352 gtk_tree_row_reference_free (priv->next_row_reference);
1355 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1356 select_next_valid_row (priv->header_model,
1357 &(priv->next_row_reference), FALSE, priv->is_outbox);
1359 /* Connect the remaining callbacks to become able to detect
1360 * changes in header-view. */
1361 priv->row_changed_handler =
1362 g_signal_connect (priv->header_model, "row-changed",
1363 G_CALLBACK (modest_msg_view_window_on_row_changed),
1365 priv->row_deleted_handler =
1366 g_signal_connect (priv->header_model, "row-deleted",
1367 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1369 priv->rows_reordered_handler =
1370 g_signal_connect (priv->header_model, "rows-reordered",
1371 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1374 check_dimming_rules_after_change (window);
1378 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1382 ModestMsgViewWindow *window)
1384 ModestMsgViewWindowPrivate *priv = NULL;
1385 gboolean already_changed = FALSE;
1387 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1389 /* If the current row was reordered select the proper next
1390 valid row. The same if the next row reference changes */
1391 if (!priv->row_reference ||
1392 !gtk_tree_row_reference_valid (priv->row_reference))
1395 if (priv->next_row_reference &&
1396 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1397 GtkTreePath *cur, *next;
1398 /* Check that the order is still the correct one */
1399 cur = gtk_tree_row_reference_get_path (priv->row_reference);
1400 next = gtk_tree_row_reference_get_path (priv->next_row_reference);
1401 gtk_tree_path_next (cur);
1402 if (gtk_tree_path_compare (cur, next) != 0) {
1403 gtk_tree_row_reference_free (priv->next_row_reference);
1404 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1405 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1406 already_changed = TRUE;
1408 gtk_tree_path_free (cur);
1409 gtk_tree_path_free (next);
1411 if (priv->next_row_reference)
1412 gtk_tree_row_reference_free (priv->next_row_reference);
1413 /* Update next row reference */
1414 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1415 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1416 already_changed = TRUE;
1419 check_dimming_rules_after_change (window);
1422 /* The modest_msg_view_window_update_model_replaced implements update
1423 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1424 * actually belongs to the header-view is the same as the TnyFolder of
1425 * the message of msg-view or not. If they are different, there is
1426 * nothing to do. If they are the same, then the model has replaced and
1427 * the reference in msg-view shall be replaced from the old model to
1428 * the new model. In this case the view will be detached from it's
1429 * header folder. From this point the next/prev buttons are dimmed.
1432 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1433 GtkTreeModel *model,
1434 const gchar *tny_folder_id)
1436 ModestMsgViewWindowPrivate *priv = NULL;
1437 ModestMsgViewWindow *window = NULL;
1439 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1440 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1442 window = MODEST_MSG_VIEW_WINDOW(observer);
1443 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1445 /* If there is an other folder in the header-view then we do
1446 * not care about it's model (msg list). Else if the
1447 * header-view shows the folder the msg shown by us is in, we
1448 * shall replace our model reference and make some check. */
1449 if(model == NULL || tny_folder_id == NULL ||
1450 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1453 /* Model is changed(replaced), so we should forget the old
1454 * one. Because there might be other references and there
1455 * might be some change on the model even if we unreferenced
1456 * it, we need to disconnect our signals here. */
1457 if (priv->header_model) {
1458 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1459 priv->row_changed_handler))
1460 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1461 priv->row_changed_handler);
1462 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1463 priv->row_deleted_handler))
1464 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1465 priv->row_deleted_handler);
1466 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1467 priv->row_inserted_handler))
1468 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1469 priv->row_inserted_handler);
1470 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1471 priv->rows_reordered_handler))
1472 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1473 priv->rows_reordered_handler);
1476 if (priv->row_reference)
1477 gtk_tree_row_reference_free (priv->row_reference);
1478 if (priv->next_row_reference)
1479 gtk_tree_row_reference_free (priv->next_row_reference);
1480 g_object_unref(priv->header_model);
1483 priv->row_changed_handler = 0;
1484 priv->row_deleted_handler = 0;
1485 priv->row_inserted_handler = 0;
1486 priv->rows_reordered_handler = 0;
1487 priv->next_row_reference = NULL;
1488 priv->row_reference = NULL;
1489 priv->header_model = NULL;
1492 priv->header_model = g_object_ref (model);
1494 /* Also we must connect to the new model for row insertions.
1495 * Only for insertions now. We will need other ones only after
1496 * the msg is show by msg-view is added to the new model. */
1497 priv->row_inserted_handler =
1498 g_signal_connect (priv->header_model, "row-inserted",
1499 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1502 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1503 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1507 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1509 ModestMsgViewWindowPrivate *priv= NULL;
1511 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1512 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1514 return priv->progress_hint;
1518 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1520 ModestMsgViewWindowPrivate *priv= NULL;
1522 TnyHeader *header = NULL;
1523 GtkTreePath *path = NULL;
1526 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1527 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1529 /* If the message was not obtained from a treemodel,
1530 * for instance if it was opened directly by the search UI:
1532 if (priv->header_model == NULL ||
1533 priv->row_reference == NULL ||
1534 !gtk_tree_row_reference_valid (priv->row_reference)) {
1535 msg = modest_msg_view_window_get_message (self);
1537 header = tny_msg_get_header (msg);
1538 g_object_unref (msg);
1543 /* Get iter of the currently selected message in the header view: */
1544 path = gtk_tree_row_reference_get_path (priv->row_reference);
1545 g_return_val_if_fail (path != NULL, NULL);
1546 gtk_tree_model_get_iter (priv->header_model,
1550 /* Get current message header */
1551 gtk_tree_model_get (priv->header_model, &iter,
1552 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1555 gtk_tree_path_free (path);
1560 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1562 ModestMsgViewWindowPrivate *priv;
1564 g_return_val_if_fail (self, NULL);
1566 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1568 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1572 modest_msg_view_window_get_top_message (ModestMsgViewWindow *self)
1574 ModestMsgViewWindowPrivate *priv;
1576 g_return_val_if_fail (self, NULL);
1578 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1581 return g_object_ref (priv->top_msg);
1587 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1589 ModestMsgViewWindowPrivate *priv;
1591 g_return_val_if_fail (self, NULL);
1593 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1595 return (const gchar*) priv->msg_uid;
1598 /* Used for the Ctrl+F accelerator */
1600 modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
1603 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1604 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1606 if (GTK_WIDGET_VISIBLE (priv->isearch_toolbar)) {
1607 modest_msg_view_window_isearch_toolbar_close (obj, data);
1609 modest_msg_view_window_show_isearch_toolbar (obj, data);
1613 /* Handler for menu option */
1615 modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj,
1618 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1619 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1621 gtk_widget_show (priv->isearch_toolbar);
1622 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1625 /* Handler for click on the "X" close button in isearch toolbar */
1627 modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
1628 ModestMsgViewWindow *obj)
1630 ModestMsgViewWindowPrivate *priv;
1632 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1635 gtk_widget_hide (priv->isearch_toolbar);
1636 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1640 modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
1641 ModestMsgViewWindow *obj)
1643 const gchar *current_search;
1644 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1646 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1647 modest_platform_system_banner (NULL, NULL, _("mail_ib_nothing_to_find"));
1651 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
1653 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1654 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
1658 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1660 g_free (priv->last_search);
1661 priv->last_search = g_strdup (current_search);
1662 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1665 modest_platform_system_banner (NULL, NULL,
1666 _HL_IB_FIND_NO_MATCHES);
1667 g_free (priv->last_search);
1668 priv->last_search = NULL;
1670 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1673 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1674 modest_platform_system_banner (NULL, NULL,
1675 _HL_IB_FIND_COMPLETE);
1676 g_free (priv->last_search);
1677 priv->last_search = NULL;
1679 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1686 modest_msg_view_window_set_zoom (ModestWindow *window,
1689 ModestMsgViewWindowPrivate *priv;
1690 ModestWindowPrivate *parent_priv;
1692 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1694 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1695 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1696 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1701 modest_msg_view_window_get_zoom (ModestWindow *window)
1703 ModestMsgViewWindowPrivate *priv;
1705 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1707 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1708 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1712 modest_msg_view_window_zoom_plus (ModestWindow *window)
1715 ModestMsgViewWindowPrivate *priv;
1719 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1720 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1722 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1724 if (zoom_level >= 2.0) {
1725 modest_platform_system_banner (NULL, NULL,
1726 _CS_MAX_ZOOM_LEVEL_REACHED);
1728 } else if (zoom_level >= 1.5) {
1730 } else if (zoom_level >= 1.2) {
1732 } else if (zoom_level >= 1.0) {
1734 } else if (zoom_level >= 0.8) {
1736 } else if (zoom_level >= 0.5) {
1742 /* set zoom level */
1743 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1744 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1745 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1746 g_free (banner_text);
1747 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1753 modest_msg_view_window_zoom_minus (ModestWindow *window)
1756 ModestMsgViewWindowPrivate *priv;
1760 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1761 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1763 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1765 if (zoom_level <= 0.5) {
1766 modest_platform_system_banner (NULL, NULL,
1767 _CS_MIN_ZOOM_LEVEL_REACHED);
1769 } else if (zoom_level <= 0.8) {
1771 } else if (zoom_level <= 1.0) {
1773 } else if (zoom_level <= 1.2) {
1775 } else if (zoom_level <= 1.5) {
1777 } else if (zoom_level <= 2.0) {
1783 /* set zoom level */
1784 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1785 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1786 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1787 g_free (banner_text);
1788 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1794 modest_msg_view_window_key_event (GtkWidget *window,
1800 focus = gtk_container_get_focus_child ((GtkContainer *) window);
1802 /* for the isearch toolbar case */
1803 if (focus && GTK_IS_ENTRY (focus)) {
1804 if (event->keyval == GDK_BackSpace) {
1806 copy = gdk_event_copy ((GdkEvent *) event);
1807 gtk_widget_event (focus, copy);
1808 gdk_event_free (copy);
1818 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1821 ModestMsgViewWindowPrivate *priv;
1822 GtkTreeIter tmp_iter;
1823 gboolean is_last_selected;
1825 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1826 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1828 /*if no model (so no rows at all), then virtually we are the last*/
1829 if (!priv->header_model || !priv->row_reference)
1832 if (!gtk_tree_row_reference_valid (priv->row_reference))
1835 path = gtk_tree_row_reference_get_path (priv->row_reference);
1839 is_last_selected = TRUE;
1840 while (is_last_selected) {
1842 gtk_tree_path_next (path);
1843 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1845 gtk_tree_model_get (priv->header_model, &tmp_iter,
1846 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1849 if (msg_is_visible (header, priv->is_outbox))
1850 is_last_selected = FALSE;
1851 g_object_unref(G_OBJECT(header));
1854 gtk_tree_path_free (path);
1855 return is_last_selected;
1859 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1861 ModestMsgViewWindowPrivate *priv;
1863 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1864 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1866 return priv->header_model != NULL;
1870 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1872 ModestMsgViewWindowPrivate *priv;
1874 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1875 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1877 return priv->is_search_result;
1881 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1883 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1885 if (!check_outbox) {
1888 ModestTnySendQueueStatus status;
1889 status = modest_tny_all_send_queues_get_msg_status (header);
1890 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1891 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1896 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1899 ModestMsgViewWindowPrivate *priv;
1900 gboolean is_first_selected;
1901 GtkTreeIter tmp_iter;
1903 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1904 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1906 /*if no model (so no rows at all), then virtually we are the first*/
1907 if (!priv->header_model || !priv->row_reference)
1910 if (!gtk_tree_row_reference_valid (priv->row_reference))
1913 path = gtk_tree_row_reference_get_path (priv->row_reference);
1917 is_first_selected = TRUE;
1918 while (is_first_selected) {
1920 if(!gtk_tree_path_prev (path))
1922 /* Here the 'if' is needless for logic, but let make sure
1923 * iter is valid for gtk_tree_model_get. */
1924 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1926 gtk_tree_model_get (priv->header_model, &tmp_iter,
1927 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1930 if (msg_is_visible (header, priv->is_outbox))
1931 is_first_selected = FALSE;
1932 g_object_unref(G_OBJECT(header));
1935 gtk_tree_path_free (path);
1936 return is_first_selected;
1943 GtkTreeRowReference *row_reference;
1947 message_reader_performer (gboolean canceled,
1949 ModestWindow *parent_window,
1950 TnyAccount *account,
1953 ModestMailOperation *mail_op = NULL;
1954 MsgReaderInfo *info;
1956 info = (MsgReaderInfo *) user_data;
1957 if (canceled || err) {
1958 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1959 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (parent_window));
1963 /* Register the header - it'll be unregistered in the callback */
1965 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1967 /* New mail operation */
1968 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1969 modest_ui_actions_disk_operations_error_handler,
1972 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1974 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1976 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1977 g_object_unref (mail_op);
1979 /* Update dimming rules */
1980 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1981 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1984 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1985 g_free (info->msg_uid);
1987 g_object_unref (info->folder);
1989 g_object_unref (info->header);
1990 g_slice_free (MsgReaderInfo, info);
1995 * Reads the message whose summary item is @header. It takes care of
1996 * several things, among others:
1998 * If the message was not previously downloaded then ask the user
1999 * before downloading. If there is no connection launch the connection
2000 * dialog. Update toolbar dimming rules.
2002 * Returns: TRUE if the mail operation was started, otherwise if the
2003 * user do not want to download the message, or if the user do not
2004 * want to connect, then the operation is not issued
2007 message_reader (ModestMsgViewWindow *window,
2008 ModestMsgViewWindowPrivate *priv,
2010 const gchar *msg_uid,
2012 GtkTreeRowReference *row_reference)
2014 ModestWindowMgr *mgr;
2015 TnyAccount *account = NULL;
2016 MsgReaderInfo *info;
2018 /* We set the header from model while we're loading */
2019 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
2020 modest_window_set_title (MODEST_WINDOW (window), _CS_UPDATING);
2026 g_object_ref (folder);
2028 mgr = modest_runtime_get_window_mgr ();
2029 /* Msg download completed */
2030 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
2032 /* Ask the user if he wants to download the message if
2034 if (!tny_device_is_online (modest_runtime_get_device())) {
2035 GtkResponseType response;
2036 GtkWindow *toplevel;
2038 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
2039 response = modest_platform_run_confirmation_dialog (toplevel, _("mcen_nc_get_msg"));
2040 if (response == GTK_RESPONSE_CANCEL) {
2041 update_window_title (window);
2046 folder = tny_header_get_folder (header);
2048 info = g_slice_new (MsgReaderInfo);
2049 info->msg_uid = g_strdup (msg_uid);
2051 info->header = g_object_ref (header);
2053 info->header = NULL;
2055 info->folder = g_object_ref (folder);
2057 info->folder = NULL;
2058 if (row_reference) {
2059 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2061 info->row_reference = NULL;
2064 /* Offer the connection dialog if necessary */
2065 modest_platform_connect_if_remote_and_perform ((ModestWindow *) window,
2067 TNY_FOLDER_STORE (folder),
2068 message_reader_performer,
2071 g_object_unref (folder);
2077 folder = tny_header_get_folder (header);
2080 account = tny_folder_get_account (folder);
2082 info = g_slice_new (MsgReaderInfo);
2083 info->msg_uid = g_strdup (msg_uid);
2085 info->folder = g_object_ref (folder);
2087 info->folder = NULL;
2089 info->header = g_object_ref (header);
2091 info->header = NULL;
2093 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2095 info->row_reference = NULL;
2097 message_reader_performer (FALSE, NULL, (ModestWindow *) window, account, info);
2099 g_object_unref (account);
2101 g_object_unref (folder);
2107 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2109 ModestMsgViewWindowPrivate *priv;
2110 GtkTreePath *path= NULL;
2111 GtkTreeIter tmp_iter;
2113 gboolean retval = TRUE;
2114 GtkTreeRowReference *row_reference = NULL;
2116 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2117 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2119 if (!priv->row_reference)
2122 /* Update the next row reference if it's not valid. This could
2123 happen if for example the header which it was pointing to,
2124 was deleted. The best place to do it is in the row-deleted
2125 handler but the tinymail model do not work like the glib
2126 tree models and reports the deletion when the row is still
2128 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2129 if (priv->next_row_reference) {
2130 gtk_tree_row_reference_free (priv->next_row_reference);
2132 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2133 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2134 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2136 priv->next_row_reference = NULL;
2139 if (priv->next_row_reference)
2140 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2144 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2146 gtk_tree_model_get_iter (priv->header_model,
2149 gtk_tree_path_free (path);
2151 gtk_tree_model_get (priv->header_model, &tmp_iter,
2152 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2155 /* Read the message & show it */
2156 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2159 gtk_tree_row_reference_free (row_reference);
2162 g_object_unref (header);
2168 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2170 ModestMsgViewWindowPrivate *priv = NULL;
2172 gboolean finished = FALSE;
2173 gboolean retval = FALSE;
2175 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2176 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2178 if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
2179 gtk_tree_row_reference_free (priv->row_reference);
2180 priv->row_reference = NULL;
2183 /* Return inmediatly if there is no header model */
2184 if (!priv->header_model || !priv->row_reference)
2187 path = gtk_tree_row_reference_get_path (priv->row_reference);
2188 while (!finished && gtk_tree_path_prev (path)) {
2192 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2193 gtk_tree_model_get (priv->header_model, &iter,
2194 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2198 if (msg_is_visible (header, priv->is_outbox)) {
2199 GtkTreeRowReference *row_reference;
2200 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2201 /* Read the message & show it */
2202 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2203 gtk_tree_row_reference_free (row_reference);
2207 g_object_unref (header);
2211 gtk_tree_path_free (path);
2216 view_msg_cb (ModestMailOperation *mail_op,
2223 ModestMsgViewWindow *self = NULL;
2224 ModestMsgViewWindowPrivate *priv = NULL;
2225 GtkTreeRowReference *row_reference = NULL;
2227 /* Unregister the header (it was registered before creating the mail operation) */
2228 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2230 row_reference = (GtkTreeRowReference *) user_data;
2233 gtk_tree_row_reference_free (row_reference);
2234 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2236 /* Restore window title */
2237 update_window_title (self);
2238 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2239 g_object_unref (self);
2244 /* If there was any error */
2245 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2247 gtk_tree_row_reference_free (row_reference);
2248 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2250 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2251 /* First we check if the parent is a folder window */
2252 if (priv->msg_uid && !modest_window_mgr_get_folder_window (MODEST_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2254 TnyAccount *account = NULL;
2255 GtkWidget *header_window = NULL;
2257 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2259 /* Get the account */
2261 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2264 if (is_merge || account) {
2265 TnyFolder *folder = NULL;
2267 /* Try to get the message, if it's already downloaded
2268 we don't need to connect */
2270 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2273 ModestTnyAccountStore *account_store;
2274 ModestTnyLocalFoldersAccount *local_folders_account;
2276 account_store = modest_runtime_get_account_store ();
2277 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2278 modest_tny_account_store_get_local_folders_account (account_store));
2279 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2280 g_object_unref (local_folders_account);
2282 if (account) g_object_unref (account);
2285 header_window = (GtkWidget *)
2286 modest_header_window_new (
2288 modest_window_get_active_account (MODEST_WINDOW (self)),
2289 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2290 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2291 MODEST_WINDOW (header_window),
2293 gtk_widget_destroy (GTK_WIDGET (header_window));
2295 gtk_widget_show_all (GTK_WIDGET (header_window));
2297 g_object_unref (folder);
2303 /* Restore window title */
2304 update_window_title (self);
2305 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2306 g_object_unref (self);
2311 /* Get the window */
2312 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2313 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2314 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2316 /* Update the row reference */
2317 if (priv->row_reference != NULL) {
2318 gtk_tree_row_reference_free (priv->row_reference);
2319 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2320 if (priv->next_row_reference != NULL) {
2321 gtk_tree_row_reference_free (priv->next_row_reference);
2323 if (priv->row_reference) {
2324 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2325 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2327 priv->next_row_reference = NULL;
2331 /* Mark header as read */
2332 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2333 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2335 /* Set new message */
2336 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2337 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2338 modest_msg_view_window_update_priority (self);
2339 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2340 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2341 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2344 /* Set the new message uid of the window */
2345 if (priv->msg_uid) {
2346 g_free (priv->msg_uid);
2347 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2350 /* Notify the observers */
2351 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2352 0, priv->header_model, priv->row_reference);
2354 /* Sync the flags if the message is not opened from a header
2355 model, i.e, if it's opened from a notification */
2356 if (!priv->header_model)
2360 g_object_unref (self);
2362 gtk_tree_row_reference_free (row_reference);
2366 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2368 ModestMsgViewWindowPrivate *priv;
2370 TnyFolderType folder_type;
2372 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2374 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2376 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2380 folder = tny_msg_get_folder (msg);
2382 folder_type = modest_tny_folder_guess_folder_type (folder);
2383 g_object_unref (folder);
2385 g_object_unref (msg);
2393 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2395 ModestMsgViewWindowPrivate *priv;
2396 TnyHeader *header = NULL;
2397 TnyHeaderFlags flags = 0;
2399 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2401 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2403 GtkTreePath *path = NULL;
2405 path = gtk_tree_row_reference_get_path (priv->row_reference);
2406 g_return_if_fail (path != NULL);
2407 gtk_tree_model_get_iter (priv->header_model,
2409 gtk_tree_row_reference_get_path (priv->row_reference));
2411 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2413 gtk_tree_path_free (path);
2416 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2418 header = tny_msg_get_header (msg);
2419 g_object_unref (msg);
2424 flags = tny_header_get_flags (header);
2425 g_object_unref(G_OBJECT(header));
2428 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2433 toolbar_resize (ModestMsgViewWindow *self)
2435 ModestMsgViewWindowPrivate *priv = NULL;
2436 ModestWindowPrivate *parent_priv = NULL;
2438 gint static_button_size;
2439 ModestWindowMgr *mgr;
2441 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2442 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2443 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2445 mgr = modest_runtime_get_window_mgr ();
2446 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2448 if (parent_priv->toolbar) {
2449 /* Set expandable and homogeneous tool buttons */
2450 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2451 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2452 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2453 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2454 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2455 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2456 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2457 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2458 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2459 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2460 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2461 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2462 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2463 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2464 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2465 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2466 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2467 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2468 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2473 modest_msg_view_window_show_toolbar (ModestWindow *self,
2474 gboolean show_toolbar)
2476 ModestMsgViewWindowPrivate *priv = NULL;
2477 ModestWindowPrivate *parent_priv;
2479 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2480 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2482 /* Set optimized view status */
2483 priv->optimized_view = !show_toolbar;
2485 if (!parent_priv->toolbar) {
2486 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2489 #ifdef MODEST_TOOLKIT_HILDON2
2490 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2492 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), GTK_ICON_SIZE_LARGE_TOOLBAR);
2494 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2496 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2497 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2498 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2500 modest_window_add_toolbar (MODEST_WINDOW (self),
2501 GTK_TOOLBAR (parent_priv->toolbar));
2506 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2507 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2508 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2510 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2511 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2512 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2514 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2517 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2518 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2523 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2525 ModestMsgViewWindow *window)
2527 if (!GTK_WIDGET_VISIBLE (window))
2530 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2534 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2536 ModestMsgViewWindowPrivate *priv;
2538 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2539 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2541 return priv->progress_hint;
2545 observers_empty (ModestMsgViewWindow *self)
2548 ModestMsgViewWindowPrivate *priv;
2549 gboolean is_empty = TRUE;
2550 guint pending_ops = 0;
2552 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2553 tmp = priv->progress_widgets;
2555 /* Check all observers */
2556 while (tmp && is_empty) {
2557 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2558 is_empty = pending_ops == 0;
2560 tmp = g_slist_next(tmp);
2567 on_account_removed (TnyAccountStore *account_store,
2568 TnyAccount *account,
2571 /* Do nothing if it's a transport account, because we only
2572 show the messages of a store account */
2573 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2574 const gchar *parent_acc = NULL;
2575 const gchar *our_acc = NULL;
2577 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2578 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2580 /* Close this window if I'm showing a message of the removed account */
2581 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2582 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2587 on_mail_operation_started (ModestMailOperation *mail_op,
2590 ModestMsgViewWindow *self;
2591 ModestMailOperationTypeOperation op_type;
2593 ModestMsgViewWindowPrivate *priv;
2594 GObject *source = NULL;
2596 self = MODEST_MSG_VIEW_WINDOW (user_data);
2597 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2598 op_type = modest_mail_operation_get_type_operation (mail_op);
2599 tmp = priv->progress_widgets;
2600 source = modest_mail_operation_get_source(mail_op);
2601 if (G_OBJECT (self) == source) {
2602 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2603 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2604 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2605 set_progress_hint (self, TRUE);
2607 modest_progress_object_add_operation (
2608 MODEST_PROGRESS_OBJECT (tmp->data),
2610 tmp = g_slist_next (tmp);
2614 g_object_unref (source);
2616 /* Update dimming rules */
2617 check_dimming_rules_after_change (self);
2621 on_mail_operation_finished (ModestMailOperation *mail_op,
2624 ModestMsgViewWindow *self;
2625 ModestMailOperationTypeOperation op_type;
2627 ModestMsgViewWindowPrivate *priv;
2629 self = MODEST_MSG_VIEW_WINDOW (user_data);
2630 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2631 op_type = modest_mail_operation_get_type_operation (mail_op);
2632 tmp = priv->progress_widgets;
2634 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2635 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2636 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2638 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2640 tmp = g_slist_next (tmp);
2643 /* If no more operations are being observed, NORMAL mode is enabled again */
2644 if (observers_empty (self)) {
2645 set_progress_hint (self, FALSE);
2649 /* Update dimming rules. We have to do this right here
2650 and not in view_msg_cb because at that point the
2651 transfer mode is still enabled so the dimming rule
2652 won't let the user delete the message that has been
2653 readed for example */
2654 check_dimming_rules_after_change (self);
2658 on_queue_changed (ModestMailOperationQueue *queue,
2659 ModestMailOperation *mail_op,
2660 ModestMailOperationQueueNotification type,
2661 ModestMsgViewWindow *self)
2663 ModestMsgViewWindowPrivate *priv;
2665 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2667 /* If this operations was created by another window, do nothing */
2668 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2671 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2672 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2674 "operation-started",
2675 G_CALLBACK (on_mail_operation_started),
2677 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2679 "operation-finished",
2680 G_CALLBACK (on_mail_operation_finished),
2682 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2683 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2685 "operation-started");
2686 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2688 "operation-finished");
2693 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2695 ModestMsgViewWindowPrivate *priv;
2696 TnyList *selected_attachments = NULL;
2698 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2699 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2701 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2702 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2704 return selected_attachments;
2708 ModestMsgViewWindow *self;
2710 gchar *attachment_uid;
2711 } DecodeAsyncHelper;
2714 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2720 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2721 const gchar *content_type;
2722 ModestMsgViewWindowPrivate *priv;
2724 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2726 if (cancelled || err) {
2729 if ((err->domain == TNY_ERROR_DOMAIN) &&
2730 (err->code == TNY_IO_ERROR_WRITE) &&
2731 (errno == ENOSPC)) {
2732 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2734 msg = g_strdup (_("mail_ib_file_operation_failed"));
2736 modest_platform_information_banner (NULL, NULL, msg);
2742 /* It could happen that the window was closed. So we
2743 assume it is a cancelation */
2744 if (!GTK_WIDGET_VISIBLE (helper->self))
2747 /* Remove the progress hint */
2748 set_progress_hint (helper->self, FALSE);
2750 content_type = tny_mime_part_get_content_type (mime_part);
2751 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2752 ModestWindowMgr *mgr;
2753 ModestWindow *msg_win = NULL;
2756 const gchar *mailbox;
2757 TnyStream *file_stream;
2760 fd = g_open (helper->file_path, O_RDONLY, 0644);
2763 file_stream = tny_fs_stream_new (fd);
2765 mgr = modest_runtime_get_window_mgr ();
2767 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2768 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2771 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2773 msg = tny_camel_msg_new ();
2774 tny_camel_msg_parse (TNY_CAMEL_MSG (msg), file_stream);
2777 top_msg = g_object_ref (priv->top_msg);
2779 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2781 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2782 account, mailbox, helper->attachment_uid);
2783 if (top_msg) g_object_unref (top_msg);
2784 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2785 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2786 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2787 gtk_widget_show_all (GTK_WIDGET (msg_win));
2789 gtk_widget_destroy (GTK_WIDGET (msg_win));
2790 g_object_unref (msg);
2791 g_object_unref (file_stream);
2793 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2798 /* make the file read-only */
2799 g_chmod(helper->file_path, 0444);
2801 /* Activate the file */
2802 modest_platform_activate_file (helper->file_path, content_type);
2807 g_object_unref (helper->self);
2808 g_free (helper->file_path);
2809 g_free (helper->attachment_uid);
2810 g_slice_free (DecodeAsyncHelper, helper);
2814 view_attachment_connect_handler (gboolean canceled,
2816 GtkWindow *parent_window,
2817 TnyAccount *account,
2821 if (canceled || err) {
2822 g_object_unref (part);
2826 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2828 g_object_unref (part);
2832 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2833 TnyMimePart *mime_part)
2835 ModestMsgViewWindowPrivate *priv;
2836 const gchar *msg_uid;
2837 gchar *attachment_uid = NULL;
2838 gint attachment_index = 0;
2839 TnyList *attachments;
2841 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2842 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2843 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2845 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2846 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2847 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2848 g_object_unref (attachments);
2850 if (msg_uid && attachment_index >= 0) {
2851 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2854 if (mime_part == NULL) {
2855 gboolean error = FALSE;
2856 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2857 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2859 } else if (tny_list_get_length (selected_attachments) > 1) {
2860 modest_platform_system_banner (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2864 iter = tny_list_create_iterator (selected_attachments);
2865 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2866 g_object_unref (iter);
2868 if (selected_attachments)
2869 g_object_unref (selected_attachments);
2874 g_object_ref (mime_part);
2877 if (tny_mime_part_is_purged (mime_part))
2880 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2881 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2883 TnyAccount *account;
2885 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2887 /* Get the account */
2889 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2892 if (!tny_device_is_online (modest_runtime_get_device())) {
2893 modest_platform_connect_and_perform ((ModestWindow *) window,
2895 TNY_ACCOUNT (account),
2896 (ModestConnectedPerformer) view_attachment_connect_handler,
2897 g_object_ref (mime_part));
2902 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2903 gchar *filepath = NULL;
2904 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2905 gboolean show_error_banner = FALSE;
2906 TnyFsStream *temp_stream = NULL;
2907 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2910 if (temp_stream != NULL) {
2911 ModestAccountMgr *mgr;
2912 DecodeAsyncHelper *helper;
2913 gboolean decode_in_provider;
2914 ModestProtocol *protocol;
2915 const gchar *account;
2917 /* Activate progress hint */
2918 set_progress_hint (window, TRUE);
2920 helper = g_slice_new0 (DecodeAsyncHelper);
2921 helper->self = g_object_ref (window);
2922 helper->file_path = g_strdup (filepath);
2923 helper->attachment_uid = g_strdup (attachment_uid);
2925 decode_in_provider = FALSE;
2926 mgr = modest_runtime_get_account_mgr ();
2927 account = modest_window_get_active_account (MODEST_WINDOW (window));
2928 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2929 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2931 uri = g_strconcat ("file://", filepath, NULL);
2932 decode_in_provider =
2933 modest_account_protocol_decode_part_to_stream_async (
2934 MODEST_ACCOUNT_PROTOCOL (protocol),
2937 TNY_STREAM (temp_stream),
2938 on_decode_to_stream_async_handler,
2945 if (!decode_in_provider)
2946 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2947 on_decode_to_stream_async_handler,
2950 g_object_unref (temp_stream);
2951 /* NOTE: files in the temporary area will be automatically
2952 * cleaned after some time if they are no longer in use */
2955 const gchar *content_type;
2956 /* the file may already exist but it isn't writable,
2957 * let's try to open it anyway */
2958 content_type = tny_mime_part_get_content_type (mime_part);
2959 modest_platform_activate_file (filepath, content_type);
2961 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2962 show_error_banner = TRUE;
2967 if (show_error_banner)
2968 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2969 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2970 ModestWindowMgr *mgr;
2971 ModestWindow *msg_win = NULL;
2972 TnyMsg *current_msg;
2976 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2977 mgr = modest_runtime_get_window_mgr ();
2978 header = tny_msg_get_header (TNY_MSG (current_msg));
2979 found = modest_window_mgr_find_registered_message_uid (mgr,
2984 g_debug ("window for this body is already being created");
2988 /* it's not found, so create a new window for it */
2989 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2990 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2991 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2993 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2996 top_msg = g_object_ref (priv->top_msg);
2998 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3000 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
3001 account, mailbox, attachment_uid);
3003 if (top_msg) g_object_unref (top_msg);
3005 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3006 modest_window_get_zoom (MODEST_WINDOW (window)));
3007 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3008 gtk_widget_show_all (GTK_WIDGET (msg_win));
3010 gtk_widget_destroy (GTK_WIDGET (msg_win));
3012 g_object_unref (current_msg);
3014 /* message attachment */
3015 TnyHeader *header = NULL;
3016 ModestWindowMgr *mgr;
3017 ModestWindow *msg_win = NULL;
3020 header = tny_msg_get_header (TNY_MSG (mime_part));
3021 mgr = modest_runtime_get_window_mgr ();
3022 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3025 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3026 * thus, we don't do anything */
3027 g_debug ("window for is already being created");
3030 /* it's not found, so create a new window for it */
3031 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3032 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3033 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3035 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3037 top_msg = g_object_ref (priv->top_msg);
3039 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3040 msg_win = modest_msg_view_window_new_for_attachment (
3041 TNY_MSG (mime_part), top_msg, account,
3042 mailbox, attachment_uid);
3043 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3044 modest_window_get_zoom (MODEST_WINDOW (window)));
3045 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3046 gtk_widget_show_all (GTK_WIDGET (msg_win));
3048 gtk_widget_destroy (GTK_WIDGET (msg_win));
3054 g_free (attachment_uid);
3056 g_object_unref (mime_part);
3068 GnomeVFSResult result;
3070 ModestMsgViewWindow *window;
3073 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3074 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3075 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3076 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3079 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3083 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3084 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3085 g_free (pair->filename);
3086 g_object_unref (pair->part);
3087 g_slice_free (SaveMimePartPair, pair);
3089 g_list_free (info->pairs);
3092 g_object_unref (info->window);
3093 info->window = NULL;
3095 g_slice_free (SaveMimePartInfo, info);
3100 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3102 /* This is a GDK lock because we are an idle callback and
3103 * modest_platform_system_banner is or does Gtk+ code */
3105 gdk_threads_enter (); /* CHECKED */
3106 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3108 } else if (info->result == GNOME_VFS_OK) {
3109 modest_platform_system_banner (NULL, NULL, _CS_SAVED);
3110 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3113 /* Check if the uri belongs to the external mmc */
3114 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3115 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3117 msg = g_strdup (_KR("cerm_memory_card_full"));
3118 modest_platform_information_banner (NULL, NULL, msg);
3121 modest_platform_system_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
3123 set_progress_hint (info->window, FALSE);
3124 save_mime_part_info_free (info, FALSE);
3125 gdk_threads_leave (); /* CHECKED */
3131 save_mime_part_to_file_connect_handler (gboolean canceled,
3133 GtkWindow *parent_window,
3134 TnyAccount *account,
3135 SaveMimePartInfo *info)
3137 if (canceled || err) {
3138 if (canceled && !err) {
3139 info->result = GNOME_VFS_ERROR_CANCELLED;
3141 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3143 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3148 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3151 TnyAccount *account;
3152 ModestMsgViewWindowPrivate *priv;
3154 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3156 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3159 /* Get the account */
3161 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3164 modest_platform_connect_and_perform ((ModestWindow *) info->window,
3166 TNY_ACCOUNT (account),
3167 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3171 g_object_unref (account);
3177 save_mime_part_to_file (SaveMimePartInfo *info)
3179 GnomeVFSHandle *handle;
3181 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3183 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3184 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3185 gboolean check_online = TRUE;
3186 ModestMsgViewWindowPrivate *priv = NULL;
3188 /* Check if we really need to connect to save the mime part */
3189 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3190 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3191 check_online = FALSE;
3193 TnyAccountStore *acc_store;
3194 TnyAccount *account = NULL;
3196 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3197 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3200 if (tny_account_get_connection_status (account) ==
3201 TNY_CONNECTION_STATUS_CONNECTED)
3202 check_online = FALSE;
3203 g_object_unref (account);
3205 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3210 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3215 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3216 if (info->result == GNOME_VFS_OK) {
3217 GError *error = NULL;
3218 gboolean decode_in_provider;
3220 ModestAccountMgr *mgr;
3221 const gchar *account;
3222 ModestProtocol *protocol = NULL;
3224 stream = tny_vfs_stream_new (handle);
3226 decode_in_provider = FALSE;
3227 mgr = modest_runtime_get_account_mgr ();
3228 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3229 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3230 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3231 decode_in_provider =
3232 modest_account_protocol_decode_part_to_stream (
3233 MODEST_ACCOUNT_PROTOCOL (protocol),
3241 if (!decode_in_provider)
3242 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3245 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3247 if (error && (error->domain == TNY_ERROR_DOMAIN) &&
3248 (error->code == TNY_IO_ERROR_WRITE) &&
3249 (errno == ENOSPC)) {
3250 info->result = GNOME_VFS_ERROR_NO_SPACE;
3252 info->result = GNOME_VFS_ERROR_IO;
3255 g_object_unref (G_OBJECT (stream));
3257 g_warning ("Could not create save attachment %s: %s\n",
3258 pair->filename, gnome_vfs_result_to_string (info->result));
3261 /* Go on saving remaining files */
3262 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3263 if (info->pairs != NULL) {
3264 save_mime_part_to_file (info);
3266 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3273 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3274 SaveMimePartInfo *info)
3276 gboolean is_ok = TRUE;
3277 gint replaced_files = 0;
3278 const GList *files = info->pairs;
3279 const GList *iter, *to_replace = NULL;
3281 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3282 SaveMimePartPair *pair = iter->data;
3283 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3285 if (modest_utils_file_exists (unescaped)) {
3287 if (replaced_files == 1)
3292 if (replaced_files) {
3295 if (replaced_files == 1) {
3296 SaveMimePartPair *pair = to_replace->data;
3297 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3298 gchar *escaped_basename, *message;
3300 escaped_basename = g_uri_unescape_string (basename, NULL);
3301 message = g_strdup_printf ("%s\n%s",
3303 (escaped_basename) ? escaped_basename : "");
3304 response = modest_platform_run_confirmation_dialog (parent, message);
3306 g_free (escaped_basename);
3308 response = modest_platform_run_confirmation_dialog (parent,
3309 _FM_REPLACE_MULTIPLE);
3311 if (response != GTK_RESPONSE_OK)
3316 save_mime_part_info_free (info, TRUE);
3318 /* Start progress and launch thread */
3319 set_progress_hint (info->window, TRUE);
3320 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3325 typedef struct _SaveAttachmentsInfo {
3326 TnyList *attachments_list;
3327 ModestMsgViewWindow *window;
3328 } SaveAttachmentsInfo;
3331 save_attachments_response (GtkDialog *dialog,
3335 TnyList *mime_parts;
3337 GList *files_to_save = NULL;
3338 gchar *current_folder;
3339 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3341 mime_parts = TNY_LIST (sa_info->attachments_list);
3343 if (arg1 != GTK_RESPONSE_OK)
3346 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3347 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3348 if (current_folder && *current_folder != '\0') {
3350 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3351 current_folder,&err);
3353 g_debug ("Error storing latest used folder: %s", err->message);
3357 g_free (current_folder);
3359 if (!modest_utils_folder_writable (chooser_uri)) {
3360 const gchar *err_msg;
3362 #ifdef MODEST_PLATFORM_MAEMO
3363 if (modest_maemo_utils_in_usb_mode ()) {
3364 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3366 err_msg = _FM_READ_ONLY_LOCATION;
3369 err_msg = _FM_READ_ONLY_LOCATION;
3371 modest_platform_system_banner (NULL, NULL, err_msg);
3375 iter = tny_list_create_iterator (mime_parts);
3376 while (!tny_iterator_is_done (iter)) {
3377 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3379 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3380 !tny_mime_part_is_purged (mime_part) &&
3381 (tny_mime_part_get_filename (mime_part) != NULL)) {
3382 SaveMimePartPair *pair;
3384 pair = g_slice_new0 (SaveMimePartPair);
3386 if (tny_list_get_length (mime_parts) > 1) {
3388 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3389 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3392 pair->filename = g_strdup (chooser_uri);
3394 pair->part = mime_part;
3395 files_to_save = g_list_prepend (files_to_save, pair);
3397 tny_iterator_next (iter);
3399 g_object_unref (iter);
3402 if (files_to_save != NULL) {
3403 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3404 info->pairs = files_to_save;
3405 info->result = TRUE;
3406 info->uri = g_strdup (chooser_uri);
3407 info->window = g_object_ref (sa_info->window);
3408 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3410 g_free (chooser_uri);
3413 /* Free and close the dialog */
3414 g_object_unref (mime_parts);
3415 g_object_unref (sa_info->window);
3416 g_slice_free (SaveAttachmentsInfo, sa_info);
3417 gtk_widget_destroy (GTK_WIDGET (dialog));
3421 msg_is_attachment (TnyList *mime_parts)
3424 gboolean retval = FALSE;
3426 if (tny_list_get_length (mime_parts) > 1)
3429 iter = tny_list_create_iterator (mime_parts);
3431 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3433 if (TNY_IS_MSG (part))
3435 g_object_unref (part);
3437 g_object_unref (iter);
3443 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3444 TnyList *mime_parts)
3446 ModestMsgViewWindowPrivate *priv;
3447 GtkWidget *save_dialog = NULL;
3448 gchar *conf_folder = NULL;
3449 gchar *filename = NULL;
3450 gchar *save_multiple_str = NULL;
3451 const gchar *root_folder = "file:///";
3453 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3454 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3456 if (mime_parts == NULL) {
3457 gboolean allow_msgs = FALSE;
3459 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3460 * selection available */
3461 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3463 /* Check if the message is composed by an unique MIME
3464 part whose content disposition is attachment. There
3465 could be messages like this:
3467 Date: Tue, 12 Jan 2010 20:40:59 +0000
3468 From: <sender@example.org>
3469 To: <recipient@example.org>
3471 Content-Type: image/jpeg
3472 Content-Disposition: attachment; filename="bug7718.jpeg"
3474 whose unique MIME part is the message itself whose
3475 content disposition is attachment
3477 if (mime_parts && msg_is_attachment (mime_parts))
3480 if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, allow_msgs)) {
3481 g_object_unref (mime_parts);
3485 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3487 g_object_unref (mime_parts);
3493 g_object_ref (mime_parts);
3496 /* prepare dialog */
3497 if (tny_list_get_length (mime_parts) == 1) {
3499 /* only one attachment selected */
3500 iter = tny_list_create_iterator (mime_parts);
3501 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3502 g_object_unref (iter);
3503 if (!modest_tny_mime_part_is_msg (mime_part) &&
3504 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3505 !tny_mime_part_is_purged (mime_part)) {
3506 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3508 /* TODO: show any error? */
3509 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3510 g_object_unref (mime_parts);
3513 g_object_unref (mime_part);
3515 gint num = tny_list_get_length (mime_parts);
3516 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3517 "sfil_va_number_of_objects_attachment",
3518 "sfil_va_number_of_objects_attachments",
3522 /* Creation of hildon file chooser dialog for saving */
3523 save_dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
3525 (GtkWindow *) window,
3526 GTK_FILE_CHOOSER_ACTION_SAVE);
3528 /* Get last used folder */
3529 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3530 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3532 /* File chooser stops working if we select "file:///" as current folder */
3533 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3534 g_free (conf_folder);
3538 if (conf_folder && conf_folder[0] != '\0') {
3539 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3542 /* Set the default folder to documents folder */
3543 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3546 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3548 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3549 g_free (docs_folder);
3551 g_free (conf_folder);
3555 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3560 /* if multiple, set multiple string */
3561 if (save_multiple_str) {
3562 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3563 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM_SAVE_OBJECT_FILES);
3564 g_free (save_multiple_str);
3567 /* We must run this asynchronously, because the hildon dialog
3568 performs a gtk_dialog_run by itself which leads to gdk
3570 SaveAttachmentsInfo *sa_info;
3571 sa_info = g_slice_new (SaveAttachmentsInfo);
3572 sa_info->attachments_list = mime_parts;
3573 sa_info->window = g_object_ref (window);
3574 g_signal_connect (save_dialog, "response",
3575 G_CALLBACK (save_attachments_response), sa_info);
3577 gtk_widget_show_all (save_dialog);
3581 show_remove_attachment_information (gpointer userdata)
3583 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3584 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3586 /* We're outside the main lock */
3587 gdk_threads_enter ();
3589 if (priv->remove_attachment_banner != NULL) {
3590 gtk_widget_destroy (priv->remove_attachment_banner);
3591 g_object_unref (priv->remove_attachment_banner);
3594 priv->remove_attachment_banner = g_object_ref (
3595 modest_platform_animation_banner (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3597 gdk_threads_leave ();
3603 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3605 ModestMsgViewWindowPrivate *priv;
3606 TnyList *mime_parts = NULL, *tmp;
3607 gchar *confirmation_message;
3613 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3614 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3616 #ifdef MODEST_TOOLKIT_HILDON2
3617 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3618 * because we don't have selection
3620 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3622 /* Remove already purged messages from mime parts list. We use
3623 a copy of the list to remove items in the original one */
3624 tmp = tny_list_copy (mime_parts);
3625 iter = tny_list_create_iterator (tmp);
3626 while (!tny_iterator_is_done (iter)) {
3627 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3628 if (tny_mime_part_is_purged (part))
3629 tny_list_remove (mime_parts, (GObject *) part);
3631 g_object_unref (part);
3632 tny_iterator_next (iter);
3634 g_object_unref (tmp);
3635 g_object_unref (iter);
3637 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3638 tny_list_get_length (mime_parts) == 0) {
3639 g_object_unref (mime_parts);
3643 /* In gtk we get only selected attachments for the operation.
3645 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
3647 /* Remove already purged messages from mime parts list. We use
3648 a copy of the list to remove items in the original one */
3649 tmp = tny_list_copy (mime_parts);
3650 iter = tny_list_create_iterator (tmp);
3651 while (!tny_iterator_is_done (iter)) {
3652 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3653 if (tny_mime_part_is_purged (part))
3654 tny_list_remove (mime_parts, (GObject *) part);
3656 g_object_unref (part);
3657 tny_iterator_next (iter);
3659 g_object_unref (tmp);
3660 g_object_unref (iter);
3662 if (tny_list_get_length (mime_parts) == 0) {
3663 g_object_unref (mime_parts);
3668 n_attachments = tny_list_get_length (mime_parts);
3669 if (n_attachments == 1) {
3673 iter = tny_list_create_iterator (mime_parts);
3674 part = (TnyMimePart *) tny_iterator_get_current (iter);
3675 g_object_unref (iter);
3676 if (modest_tny_mime_part_is_msg (part)) {
3678 header = tny_msg_get_header (TNY_MSG (part));
3679 filename = tny_header_dup_subject (header);
3680 g_object_unref (header);
3681 if (filename == NULL)
3682 filename = g_strdup (_("mail_va_no_subject"));
3684 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3686 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3688 g_object_unref (part);
3690 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3691 "mcen_nc_purge_files_text",
3692 n_attachments), n_attachments);
3694 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3695 confirmation_message);
3696 g_free (confirmation_message);
3698 if (response != GTK_RESPONSE_OK) {
3699 g_object_unref (mime_parts);
3703 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3705 iter = tny_list_create_iterator (mime_parts);
3706 while (!tny_iterator_is_done (iter)) {
3709 part = (TnyMimePart *) tny_iterator_get_current (iter);
3710 tny_mime_part_set_purged (TNY_MIME_PART (part));
3711 g_object_unref (part);
3712 tny_iterator_next (iter);
3714 g_object_unref (iter);
3716 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3717 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3718 tny_msg_rewrite_cache (msg);
3719 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3720 g_object_unref (msg);
3721 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3723 g_object_unref (mime_parts);
3725 if (priv->purge_timeout > 0) {
3726 g_source_remove (priv->purge_timeout);
3727 priv->purge_timeout = 0;
3730 if (priv->remove_attachment_banner) {
3731 gtk_widget_destroy (priv->remove_attachment_banner);
3732 g_object_unref (priv->remove_attachment_banner);
3733 priv->remove_attachment_banner = NULL;
3739 update_window_title (ModestMsgViewWindow *window)
3741 ModestMsgViewWindowPrivate *priv;
3743 TnyHeader *header = NULL;
3744 gchar *subject = NULL;
3746 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3748 /* Note that if the window is closed while we're retrieving
3749 the message, this widget could de deleted */
3750 if (!priv->msg_view)
3753 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3755 if (priv->other_body) {
3758 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3760 g_strstrip (description);
3761 subject = description;
3763 } else if (msg != NULL) {
3764 header = tny_msg_get_header (msg);
3765 subject = tny_header_dup_subject (header);
3766 g_object_unref (header);
3767 g_object_unref (msg);
3770 if ((subject == NULL)||(subject[0] == '\0')) {
3772 subject = g_strdup (_("mail_va_no_subject"));
3775 modest_window_set_title (MODEST_WINDOW (window), subject);
3780 on_move_focus (GtkWidget *widget,
3781 GtkDirectionType direction,
3784 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3788 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3790 GnomeVFSResult result;
3791 GnomeVFSHandle *handle = NULL;
3792 GnomeVFSFileInfo *info = NULL;
3795 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3796 if (result != GNOME_VFS_OK) {
3801 info = gnome_vfs_file_info_new ();
3802 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3803 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3804 /* We put a "safe" default size for going to cache */
3805 *expected_size = (300*1024);
3807 *expected_size = info->size;
3809 gnome_vfs_file_info_unref (info);
3811 stream = tny_vfs_stream_new (handle);
3820 TnyStream *output_stream;
3821 GtkWidget *msg_view;
3826 on_fetch_image_timeout_refresh_view (gpointer userdata)
3828 ModestMsgViewWindowPrivate *priv;
3830 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3831 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3832 /* Note that priv->msg_view is set to NULL when this window is
3834 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3835 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3837 priv->fetch_image_redraw_handler = 0;
3838 g_object_unref (userdata);
3843 on_fetch_image_idle_refresh_view (gpointer userdata)
3846 FetchImageData *fidata = (FetchImageData *) userdata;
3848 gdk_threads_enter ();
3849 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3850 ModestMsgViewWindowPrivate *priv;
3852 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3853 priv->fetching_images--;
3854 if (priv->fetch_image_redraw_handler == 0) {
3855 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3859 gdk_threads_leave ();
3861 g_object_unref (fidata->msg_view);
3862 g_object_unref (fidata->window);
3863 g_slice_free (FetchImageData, fidata);
3868 on_fetch_image_thread (gpointer userdata)
3870 FetchImageData *fidata = (FetchImageData *) userdata;
3871 TnyStreamCache *cache;
3872 TnyStream *cache_stream;
3874 cache = modest_runtime_get_images_cache ();
3876 tny_stream_cache_get_stream (cache,
3878 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3879 (gpointer) fidata->uri);
3880 g_free (fidata->cache_id);
3881 g_free (fidata->uri);
3883 if (cache_stream != NULL) {
3886 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3889 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3890 if (G_UNLIKELY (nb_read < 0)) {
3892 } else if (G_LIKELY (nb_read > 0)) {
3893 gssize nb_written = 0;
3895 while (G_UNLIKELY (nb_written < nb_read)) {
3898 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3899 nb_read - nb_written);
3900 if (G_UNLIKELY (len < 0))
3906 tny_stream_close (cache_stream);
3907 g_object_unref (cache_stream);
3910 tny_stream_close (fidata->output_stream);
3911 g_object_unref (fidata->output_stream);
3913 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3919 on_fetch_image (ModestMsgView *msgview,
3922 ModestMsgViewWindow *window)
3924 const gchar *current_account;
3925 ModestMsgViewWindowPrivate *priv;
3926 FetchImageData *fidata;
3928 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3930 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3932 fidata = g_slice_new0 (FetchImageData);
3933 fidata->msg_view = g_object_ref (msgview);
3934 fidata->window = g_object_ref (window);
3935 fidata->uri = g_strdup (uri);
3936 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3937 fidata->output_stream = g_object_ref (stream);
3939 priv->fetching_images++;
3940 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3941 g_object_unref (fidata->output_stream);
3942 g_free (fidata->cache_id);
3943 g_free (fidata->uri);
3944 g_object_unref (fidata->msg_view);
3945 g_slice_free (FetchImageData, fidata);
3946 tny_stream_close (stream);
3947 priv->fetching_images--;
3948 update_progress_hint (window);
3951 update_progress_hint (window);
3957 setup_menu (ModestMsgViewWindow *self)
3959 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3961 /* Settings menu buttons */
3962 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3963 MODEST_WINDOW_MENU_CALLBACK (modest_msg_view_window_show_isearch_toolbar),
3964 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3966 modest_window_add_to_menu (MODEST_WINDOW (self),
3967 dngettext(GETTEXT_PACKAGE,
3968 "mcen_me_move_message",
3969 "mcen_me_move_messages",
3972 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_move_to),
3973 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3975 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3976 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3977 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3979 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3980 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3981 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3983 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3984 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_save_attachments),
3985 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3986 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3987 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3988 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3990 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3991 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3992 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3993 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3994 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3995 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3997 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3998 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_details),
3999 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
4003 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
4005 ModestMsgViewWindowPrivate *priv;
4006 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4007 GSList *recipients = NULL;
4010 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
4014 header = modest_msg_view_window_get_header (self);
4017 recipients = modest_tny_msg_header_get_all_recipients_list (header);
4018 g_object_unref (header);
4020 recipients = modest_tny_msg_get_all_recipients_list (msg);
4021 g_object_unref (msg);
4025 /* Offer the user to add recipients to the address book */
4026 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
4027 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
4032 _modest_msg_view_window_map_event (GtkWidget *widget,
4036 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
4038 update_progress_hint (self);
4044 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4046 ModestMsgViewWindowPrivate *priv;
4047 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4049 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4053 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4055 ModestMsgViewWindowPrivate *priv;
4056 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4058 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4060 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4064 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4066 ModestMsgViewWindowPrivate *priv;
4067 const gchar *msg_uid;
4068 TnyHeader *header = NULL;
4069 TnyFolder *folder = NULL;
4071 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4073 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4075 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4079 folder = tny_header_get_folder (header);
4080 g_object_unref (header);
4085 msg_uid = modest_msg_view_window_get_message_uid (self);
4087 GtkTreeRowReference *row_reference;
4089 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4090 row_reference = priv->row_reference;
4092 row_reference = NULL;
4094 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4095 g_warning ("Shouldn't happen, trying to reload a message failed");
4098 g_object_unref (folder);
4102 update_branding (ModestMsgViewWindow *self)
4104 const gchar *account;
4105 const gchar *mailbox;
4106 ModestAccountMgr *mgr;
4107 ModestProtocol *protocol = NULL;
4108 gchar *service_name = NULL;
4109 const GdkPixbuf *service_icon = NULL;
4110 ModestMsgViewWindowPrivate *priv;
4112 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4114 account = modest_window_get_active_account (MODEST_WINDOW (self));
4115 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4117 mgr = modest_runtime_get_account_mgr ();
4119 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4120 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4121 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4123 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4124 account, mailbox, MODEST_ICON_SIZE_SMALL);
4128 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4129 g_free (service_name);
4133 sync_flags (ModestMsgViewWindow *self)
4135 TnyHeader *header = NULL;
4137 header = modest_msg_view_window_get_header (self);
4139 TnyMsg *msg = modest_msg_view_window_get_message (self);
4141 header = tny_msg_get_header (msg);
4142 g_object_unref (msg);
4147 TnyFolder *folder = tny_header_get_folder (header);
4150 ModestMailOperation *mail_op;
4152 /* Sync folder, we need this to save the seen flag */
4153 mail_op = modest_mail_operation_new (NULL);
4154 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4156 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4157 g_object_unref (mail_op);
4158 g_object_unref (folder);
4160 g_object_unref (header);
4164 #ifdef MODEST_TOOLKIT_HILDON2
4166 on_realize (GtkWidget *widget,
4169 GdkDisplay *display;
4171 unsigned long val = 1;
4173 display = gdk_drawable_get_display (widget->window);
4174 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4175 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4176 GDK_WINDOW_XID (widget->window), atom,
4177 XA_INTEGER, 32, PropModeReplace,
4178 (unsigned char *) &val, 1);
4185 on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
4187 const gchar *account_name;
4188 ModestProtocolType proto_type;
4189 ModestProtocol *protocol;
4190 gboolean retval = FALSE;
4192 account_name = modest_window_get_active_account (MODEST_WINDOW (self));
4195 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
4198 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
4201 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4202 retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
4203 calendar_part, container);