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 g_object_ref (priv->msg_view);
583 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
584 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
586 /* NULL-ize fields if the window is destroyed */
587 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
589 gtk_widget_show_all (GTK_WIDGET(main_vbox));
593 modest_msg_view_window_disconnect_signals (ModestWindow *self)
595 ModestMsgViewWindowPrivate *priv;
596 GtkWidget *header_view = NULL;
597 GtkWindow *parent_window = NULL;
599 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
601 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
602 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
603 priv->clipboard_change_handler))
604 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
605 priv->clipboard_change_handler);
607 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
608 priv->queue_change_handler))
609 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
610 priv->queue_change_handler);
612 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
613 priv->account_removed_handler))
614 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
615 priv->account_removed_handler);
617 if (priv->header_model) {
618 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
619 priv->row_changed_handler))
620 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
621 priv->row_changed_handler);
623 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
624 priv->row_deleted_handler))
625 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
626 priv->row_deleted_handler);
628 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
629 priv->row_inserted_handler))
630 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
631 priv->row_inserted_handler);
633 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
634 priv->rows_reordered_handler))
635 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
636 priv->rows_reordered_handler);
639 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
640 priv->sighandlers = NULL;
642 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
643 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
644 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
646 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
647 MODEST_HEADER_VIEW_OBSERVER(self));
653 modest_msg_view_window_finalize (GObject *obj)
655 ModestMsgViewWindowPrivate *priv;
657 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
659 /* Sanity check: shouldn't be needed, the window mgr should
660 call this function before */
661 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
662 g_object_unref (priv->msg_view);
664 if (priv->fetch_image_redraw_handler > 0) {
665 g_source_remove (priv->fetch_image_redraw_handler);
666 priv->fetch_image_redraw_handler = 0;
669 if (priv->other_body != NULL) {
670 g_object_unref (priv->other_body);
671 priv->other_body = NULL;
674 if (priv->top_msg != NULL) {
675 g_object_unref (priv->top_msg);
676 priv->top_msg = NULL;
679 if (priv->header_model != NULL) {
680 g_object_unref (priv->header_model);
681 priv->header_model = NULL;
684 if (priv->remove_attachment_banner) {
685 gtk_widget_destroy (priv->remove_attachment_banner);
686 g_object_unref (priv->remove_attachment_banner);
687 priv->remove_attachment_banner = NULL;
690 if (priv->purge_timeout > 0) {
691 g_source_remove (priv->purge_timeout);
692 priv->purge_timeout = 0;
695 if (priv->row_reference) {
696 gtk_tree_row_reference_free (priv->row_reference);
697 priv->row_reference = NULL;
700 if (priv->next_row_reference) {
701 gtk_tree_row_reference_free (priv->next_row_reference);
702 priv->next_row_reference = NULL;
706 g_free (priv->msg_uid);
707 priv->msg_uid = NULL;
710 G_OBJECT_CLASS(parent_class)->finalize (obj);
714 select_next_valid_row (GtkTreeModel *model,
715 GtkTreeRowReference **row_reference,
719 GtkTreeIter tmp_iter;
721 GtkTreePath *next = NULL;
722 gboolean retval = FALSE, finished;
724 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
726 path = gtk_tree_row_reference_get_path (*row_reference);
727 gtk_tree_model_get_iter (model, &tmp_iter, path);
728 gtk_tree_row_reference_free (*row_reference);
729 *row_reference = NULL;
733 TnyHeader *header = NULL;
735 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
736 gtk_tree_model_get (model, &tmp_iter,
737 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
741 if (msg_is_visible (header, is_outbox)) {
742 next = gtk_tree_model_get_path (model, &tmp_iter);
743 *row_reference = gtk_tree_row_reference_new (model, next);
744 gtk_tree_path_free (next);
748 g_object_unref (header);
751 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
752 next = gtk_tree_model_get_path (model, &tmp_iter);
754 /* Ensure that we are not selecting the same */
755 if (gtk_tree_path_compare (path, next) != 0) {
756 gtk_tree_model_get (model, &tmp_iter,
757 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
760 if (msg_is_visible (header, is_outbox)) {
761 *row_reference = gtk_tree_row_reference_new (model, next);
765 g_object_unref (header);
769 /* If we ended up in the same message
770 then there is no valid next
774 gtk_tree_path_free (next);
776 /* If there are no more messages and we don't
777 want to start again in the first one then
778 there is no valid next message */
784 gtk_tree_path_free (path);
789 /* TODO: This should be in _init(), with the parameters as properties. */
791 modest_msg_view_window_construct (ModestMsgViewWindow *self,
792 const gchar *modest_account_name,
793 const gchar *mailbox,
794 const gchar *msg_uid)
797 ModestMsgViewWindowPrivate *priv = NULL;
798 ModestWindowPrivate *parent_priv = NULL;
799 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
800 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
802 obj = G_OBJECT (self);
803 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
804 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
806 priv->msg_uid = g_strdup (msg_uid);
809 parent_priv->menubar = NULL;
811 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
812 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
815 /* Add common dimming rules */
816 modest_dimming_rules_group_add_rules (toolbar_rules_group,
817 modest_msg_view_toolbar_dimming_entries,
818 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
819 MODEST_WINDOW (self));
820 modest_dimming_rules_group_add_rules (clipboard_rules_group,
821 modest_msg_view_clipboard_dimming_entries,
822 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
823 MODEST_WINDOW (self));
825 /* Insert dimming rules group for this window */
826 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
827 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
828 g_object_unref (toolbar_rules_group);
829 g_object_unref (clipboard_rules_group);
831 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
833 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);
834 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
835 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
836 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
837 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
838 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
839 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
840 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
841 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
842 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
843 G_CALLBACK (modest_ui_actions_on_details), obj);
844 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
845 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
846 g_signal_connect (G_OBJECT(priv->msg_view), "limit_error",
847 G_CALLBACK (modest_ui_actions_on_limit_error), obj);
848 g_signal_connect (G_OBJECT(priv->msg_view), "handle_calendar",
849 G_CALLBACK (on_handle_calendar), obj);
850 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
851 G_CALLBACK (on_fetch_image), obj);
853 g_signal_connect (G_OBJECT (obj), "key-release-event",
854 G_CALLBACK (modest_msg_view_window_key_event),
857 g_signal_connect (G_OBJECT (obj), "key-press-event",
858 G_CALLBACK (modest_msg_view_window_key_event),
861 g_signal_connect (G_OBJECT (obj), "move-focus",
862 G_CALLBACK (on_move_focus), obj);
864 g_signal_connect (G_OBJECT (obj), "map-event",
865 G_CALLBACK (_modest_msg_view_window_map_event),
868 /* Mail Operation Queue */
869 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
871 G_CALLBACK (on_queue_changed),
874 /* Account manager */
875 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
877 G_CALLBACK(on_account_removed),
880 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
881 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
883 /* First add out toolbar ... */
884 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
886 priv->isearch_toolbar = modest_toolkit_factory_create_isearch_toolbar (modest_runtime_get_toolkit_factory (),
888 modest_window_add_toolbar (MODEST_WINDOW (obj), GTK_TOOLBAR (priv->isearch_toolbar));
889 gtk_widget_set_no_show_all (priv->isearch_toolbar, TRUE);
890 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-close",
891 G_CALLBACK (modest_msg_view_window_isearch_toolbar_close), obj);
892 g_signal_connect (G_OBJECT (priv->isearch_toolbar), "isearch-search",
893 G_CALLBACK (modest_msg_view_window_isearch_toolbar_search), obj);
894 priv->last_search = NULL;
896 /* Init the clipboard actions dim status */
897 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
899 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
904 /* FIXME: parameter checks */
906 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
907 const gchar *modest_account_name,
908 const gchar *mailbox,
909 const gchar *msg_uid,
911 GtkTreeRowReference *row_reference)
913 ModestMsgViewWindow *window = NULL;
914 ModestMsgViewWindowPrivate *priv = NULL;
915 TnyFolder *header_folder = NULL;
916 ModestHeaderView *header_view = NULL;
917 ModestWindowMgr *mgr = NULL;
920 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
923 mgr = modest_runtime_get_window_mgr ();
924 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
925 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
927 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
929 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
930 priv->top_msg = NULL;
932 /* Remember the message list's TreeModel so we can detect changes
933 * and change the list selection when necessary: */
934 header_folder = modest_header_view_get_folder (header_view);
936 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
937 TNY_FOLDER_TYPE_OUTBOX);
938 priv->header_folder_id = tny_folder_get_id (header_folder);
939 g_object_unref(header_folder);
942 /* Setup row references and connect signals */
943 priv->header_model = g_object_ref (model);
945 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
946 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
947 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
948 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
950 priv->row_reference = NULL;
951 priv->next_row_reference = NULL;
954 /* Connect signals */
955 priv->row_changed_handler =
956 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
957 G_CALLBACK(modest_msg_view_window_on_row_changed),
959 priv->row_deleted_handler =
960 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
961 G_CALLBACK(modest_msg_view_window_on_row_deleted),
963 priv->row_inserted_handler =
964 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
965 G_CALLBACK(modest_msg_view_window_on_row_inserted),
967 priv->rows_reordered_handler =
968 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
969 G_CALLBACK(modest_msg_view_window_on_row_reordered),
972 if (header_view != NULL){
973 modest_header_view_add_observer(header_view,
974 MODEST_HEADER_VIEW_OBSERVER(window));
977 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
978 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
979 update_branding (MODEST_MSG_VIEW_WINDOW (window));
981 /* gtk_widget_show_all (GTK_WIDGET (window)); */
982 modest_msg_view_window_update_priority (window);
983 /* Check dimming rules */
984 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
985 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
986 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
988 return MODEST_WINDOW(window);
992 modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
993 const gchar *mailbox,
994 const gchar *msg_uid)
996 ModestMsgViewWindow *window = NULL;
997 ModestMsgViewWindowPrivate *priv = NULL;
998 ModestWindowMgr *mgr = NULL;
1000 TnyAccount *account = NULL;
1002 mgr = modest_runtime_get_window_mgr ();
1003 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1004 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1006 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1008 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1009 priv->top_msg = NULL;
1011 is_merge = g_str_has_prefix (msg_uid, "merge:");
1013 /* Get the account */
1015 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1018 if (is_merge || account) {
1019 TnyFolder *folder = NULL;
1021 /* Try to get the message, if it's already downloaded
1022 we don't need to connect */
1024 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
1026 ModestTnyAccountStore *account_store;
1027 ModestTnyLocalFoldersAccount *local_folders_account;
1029 account_store = modest_runtime_get_account_store ();
1030 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
1031 modest_tny_account_store_get_local_folders_account (account_store));
1032 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
1033 g_object_unref (local_folders_account);
1037 gboolean device_online;
1039 device = modest_runtime_get_device();
1040 device_online = tny_device_is_online (device);
1041 if (device_online) {
1042 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1044 TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
1046 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1047 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
1048 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1049 g_object_unref (msg);
1050 /* Sync flags to server */
1051 sync_flags (MODEST_MSG_VIEW_WINDOW (window));
1053 message_reader (window, priv, NULL, msg_uid, folder, NULL);
1056 g_object_unref (folder);
1061 /* Check dimming rules */
1062 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1063 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1064 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1066 return MODEST_WINDOW(window);
1070 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1071 const gchar *modest_account_name,
1072 const gchar *mailbox,
1073 const gchar *msg_uid,
1074 GtkTreeRowReference *row_reference)
1076 ModestMsgViewWindow *window = NULL;
1077 ModestMsgViewWindowPrivate *priv = NULL;
1078 TnyFolder *header_folder = NULL;
1079 ModestWindowMgr *mgr = NULL;
1083 mgr = modest_runtime_get_window_mgr ();
1084 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1085 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1087 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1089 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1090 priv->top_msg = NULL;
1092 /* Remember the message list's TreeModel so we can detect changes
1093 * and change the list selection when necessary: */
1095 if (header_view != NULL){
1096 header_folder = modest_header_view_get_folder(header_view);
1097 /* This could happen if the header folder was
1098 unseleted before opening this msg window (for
1099 example if the user selects an account in the
1100 folder view of the main window */
1101 if (header_folder) {
1102 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1103 TNY_FOLDER_TYPE_OUTBOX);
1104 priv->header_folder_id = tny_folder_get_id(header_folder);
1105 g_object_unref(header_folder);
1109 /* Setup row references and connect signals */
1110 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1111 g_object_ref (priv->header_model);
1113 if (row_reference && gtk_tree_row_reference_valid (row_reference)) {
1114 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1115 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1116 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1118 priv->row_reference = NULL;
1119 priv->next_row_reference = NULL;
1122 /* Connect signals */
1123 priv->row_changed_handler =
1124 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1125 G_CALLBACK(modest_msg_view_window_on_row_changed),
1127 priv->row_deleted_handler =
1128 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1129 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1131 priv->row_inserted_handler =
1132 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1133 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1135 priv->rows_reordered_handler =
1136 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1137 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1140 if (header_view != NULL){
1141 modest_header_view_add_observer(header_view,
1142 MODEST_HEADER_VIEW_OBSERVER(window));
1145 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1146 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1148 if (priv->row_reference) {
1149 path = gtk_tree_row_reference_get_path (priv->row_reference);
1150 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1152 gtk_tree_model_get (priv->header_model, &iter,
1153 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1155 message_reader (window, priv, header, NULL, NULL, priv->row_reference);
1156 g_object_unref (header);
1158 gtk_tree_path_free (path);
1160 /* Check dimming rules */
1161 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1162 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1163 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1165 return MODEST_WINDOW(window);
1169 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1170 const gchar *modest_account_name,
1171 const gchar *mailbox,
1172 const gchar *msg_uid)
1174 ModestMsgViewWindow *window = NULL;
1175 ModestMsgViewWindowPrivate *priv = NULL;
1176 ModestWindowMgr *mgr = NULL;
1178 mgr = modest_runtime_get_window_mgr ();
1179 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1180 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1181 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1183 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1184 priv->top_msg = NULL;
1186 /* Remember that this is a search result,
1187 * so we can disable some UI appropriately: */
1188 priv->is_search_result = TRUE;
1190 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1191 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1193 update_window_title (window);
1194 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1195 modest_msg_view_window_update_priority (window);
1197 /* Check dimming rules */
1198 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1199 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1200 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1202 return MODEST_WINDOW(window);
1206 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1208 ModestMsgViewWindowPrivate *priv = NULL;
1210 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1211 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1213 return (priv->other_body != NULL);
1217 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1218 TnyMimePart *other_body,
1220 const gchar *modest_account_name,
1221 const gchar *mailbox,
1222 const gchar *msg_uid)
1224 GObject *obj = NULL;
1225 ModestMsgViewWindowPrivate *priv;
1226 ModestWindowMgr *mgr = NULL;
1228 g_return_val_if_fail (msg, NULL);
1229 mgr = modest_runtime_get_window_mgr ();
1230 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1231 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1232 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1233 modest_account_name, mailbox, msg_uid);
1236 priv->other_body = g_object_ref (other_body);
1237 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1239 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1242 priv->top_msg = g_object_ref (top_msg);
1244 priv->top_msg = NULL;
1246 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1247 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1249 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1251 /* Check dimming rules */
1252 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1253 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1254 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1256 return MODEST_WINDOW(obj);
1260 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1262 const gchar *modest_account_name,
1263 const gchar *mailbox,
1264 const gchar *msg_uid)
1266 return modest_msg_view_window_new_with_other_body (msg, NULL, top_msg, modest_account_name, mailbox, msg_uid);
1270 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1273 ModestMsgViewWindow *window)
1275 check_dimming_rules_after_change (window);
1279 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1281 ModestMsgViewWindow *window)
1283 check_dimming_rules_after_change (window);
1285 /* The window could have dissapeared */
1288 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1290 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1291 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1295 /* On insertions we check if the folder still has the message we are
1296 * showing or do not. If do not, we do nothing. Which means we are still
1297 * not attached to any header folder and thus next/prev buttons are
1298 * still dimmed. Once the message that is shown by msg-view is found, the
1299 * new model of header-view will be attached and the references will be set.
1300 * On each further insertions dimming rules will be checked. However
1301 * this requires extra CPU time at least works.
1302 * (An message might be deleted from TnyFolder and thus will not be
1303 * inserted into the model again for example if it is removed by the
1304 * imap server and the header view is refreshed.)
1307 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1308 GtkTreePath *tree_path,
1309 GtkTreeIter *tree_iter,
1310 ModestMsgViewWindow *window)
1312 ModestMsgViewWindowPrivate *priv = NULL;
1313 TnyHeader *header = NULL;
1315 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1316 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1318 g_assert (model == priv->header_model);
1320 /* Check if the newly inserted message is the same we are actually
1321 * showing. IF not, we should remain detached from the header model
1322 * and thus prev and next toolbar buttons should remain dimmed. */
1323 gtk_tree_model_get (model, tree_iter,
1324 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1327 if (TNY_IS_HEADER (header)) {
1330 uid = modest_tny_folder_get_header_unique_id (header);
1331 if (!g_str_equal(priv->msg_uid, uid)) {
1332 check_dimming_rules_after_change (window);
1334 g_object_unref (G_OBJECT(header));
1338 g_object_unref(G_OBJECT(header));
1341 if (priv->row_reference) {
1342 gtk_tree_row_reference_free (priv->row_reference);
1345 /* Setup row_reference for the actual msg. */
1346 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1347 if (priv->row_reference == NULL) {
1348 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1352 /* Now set up next_row_reference. */
1353 if (priv->next_row_reference) {
1354 gtk_tree_row_reference_free (priv->next_row_reference);
1357 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1358 select_next_valid_row (priv->header_model,
1359 &(priv->next_row_reference), FALSE, priv->is_outbox);
1361 /* Connect the remaining callbacks to become able to detect
1362 * changes in header-view. */
1363 priv->row_changed_handler =
1364 g_signal_connect (priv->header_model, "row-changed",
1365 G_CALLBACK (modest_msg_view_window_on_row_changed),
1367 priv->row_deleted_handler =
1368 g_signal_connect (priv->header_model, "row-deleted",
1369 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1371 priv->rows_reordered_handler =
1372 g_signal_connect (priv->header_model, "rows-reordered",
1373 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1376 check_dimming_rules_after_change (window);
1380 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1384 ModestMsgViewWindow *window)
1386 ModestMsgViewWindowPrivate *priv = NULL;
1387 gboolean already_changed = FALSE;
1389 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1391 /* If the current row was reordered select the proper next
1392 valid row. The same if the next row reference changes */
1393 if (!priv->row_reference ||
1394 !gtk_tree_row_reference_valid (priv->row_reference))
1397 if (priv->next_row_reference &&
1398 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1399 GtkTreePath *cur, *next;
1400 /* Check that the order is still the correct one */
1401 cur = gtk_tree_row_reference_get_path (priv->row_reference);
1402 next = gtk_tree_row_reference_get_path (priv->next_row_reference);
1403 gtk_tree_path_next (cur);
1404 if (gtk_tree_path_compare (cur, next) != 0) {
1405 gtk_tree_row_reference_free (priv->next_row_reference);
1406 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1407 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1408 already_changed = TRUE;
1410 gtk_tree_path_free (cur);
1411 gtk_tree_path_free (next);
1413 if (priv->next_row_reference)
1414 gtk_tree_row_reference_free (priv->next_row_reference);
1415 /* Update next row reference */
1416 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1417 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1418 already_changed = TRUE;
1421 check_dimming_rules_after_change (window);
1424 /* The modest_msg_view_window_update_model_replaced implements update
1425 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1426 * actually belongs to the header-view is the same as the TnyFolder of
1427 * the message of msg-view or not. If they are different, there is
1428 * nothing to do. If they are the same, then the model has replaced and
1429 * the reference in msg-view shall be replaced from the old model to
1430 * the new model. In this case the view will be detached from it's
1431 * header folder. From this point the next/prev buttons are dimmed.
1434 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1435 GtkTreeModel *model,
1436 const gchar *tny_folder_id)
1438 ModestMsgViewWindowPrivate *priv = NULL;
1439 ModestMsgViewWindow *window = NULL;
1441 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1442 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1444 window = MODEST_MSG_VIEW_WINDOW(observer);
1445 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1447 /* If there is an other folder in the header-view then we do
1448 * not care about it's model (msg list). Else if the
1449 * header-view shows the folder the msg shown by us is in, we
1450 * shall replace our model reference and make some check. */
1451 if(model == NULL || tny_folder_id == NULL ||
1452 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1455 /* Model is changed(replaced), so we should forget the old
1456 * one. Because there might be other references and there
1457 * might be some change on the model even if we unreferenced
1458 * it, we need to disconnect our signals here. */
1459 if (priv->header_model) {
1460 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1461 priv->row_changed_handler))
1462 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1463 priv->row_changed_handler);
1464 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1465 priv->row_deleted_handler))
1466 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1467 priv->row_deleted_handler);
1468 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1469 priv->row_inserted_handler))
1470 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1471 priv->row_inserted_handler);
1472 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1473 priv->rows_reordered_handler))
1474 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1475 priv->rows_reordered_handler);
1478 if (priv->row_reference)
1479 gtk_tree_row_reference_free (priv->row_reference);
1480 if (priv->next_row_reference)
1481 gtk_tree_row_reference_free (priv->next_row_reference);
1482 g_object_unref(priv->header_model);
1485 priv->row_changed_handler = 0;
1486 priv->row_deleted_handler = 0;
1487 priv->row_inserted_handler = 0;
1488 priv->rows_reordered_handler = 0;
1489 priv->next_row_reference = NULL;
1490 priv->row_reference = NULL;
1491 priv->header_model = NULL;
1494 priv->header_model = g_object_ref (model);
1496 /* Also we must connect to the new model for row insertions.
1497 * Only for insertions now. We will need other ones only after
1498 * the msg is show by msg-view is added to the new model. */
1499 priv->row_inserted_handler =
1500 g_signal_connect (priv->header_model, "row-inserted",
1501 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1504 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1505 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1509 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1511 ModestMsgViewWindowPrivate *priv= NULL;
1513 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1514 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1516 return priv->progress_hint;
1520 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1522 ModestMsgViewWindowPrivate *priv= NULL;
1524 TnyHeader *header = NULL;
1525 GtkTreePath *path = NULL;
1528 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1529 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1531 /* If the message was not obtained from a treemodel,
1532 * for instance if it was opened directly by the search UI:
1534 if (priv->header_model == NULL ||
1535 priv->row_reference == NULL ||
1536 !gtk_tree_row_reference_valid (priv->row_reference)) {
1537 msg = modest_msg_view_window_get_message (self);
1539 header = tny_msg_get_header (msg);
1540 g_object_unref (msg);
1545 /* Get iter of the currently selected message in the header view: */
1546 path = gtk_tree_row_reference_get_path (priv->row_reference);
1547 g_return_val_if_fail (path != NULL, NULL);
1548 gtk_tree_model_get_iter (priv->header_model,
1552 /* Get current message header */
1553 gtk_tree_model_get (priv->header_model, &iter,
1554 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1557 gtk_tree_path_free (path);
1562 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1564 ModestMsgViewWindowPrivate *priv;
1566 g_return_val_if_fail (self, NULL);
1568 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1570 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1574 modest_msg_view_window_get_top_message (ModestMsgViewWindow *self)
1576 ModestMsgViewWindowPrivate *priv;
1578 g_return_val_if_fail (self, NULL);
1580 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1583 return g_object_ref (priv->top_msg);
1589 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1591 ModestMsgViewWindowPrivate *priv;
1593 g_return_val_if_fail (self, NULL);
1595 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1597 return (const gchar*) priv->msg_uid;
1600 /* Used for the Ctrl+F accelerator */
1602 modest_msg_view_window_toggle_isearch_toolbar (GtkWidget *obj,
1605 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1606 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1608 if (GTK_WIDGET_VISIBLE (priv->isearch_toolbar)) {
1609 modest_msg_view_window_isearch_toolbar_close (obj, data);
1611 modest_msg_view_window_show_isearch_toolbar (obj, data);
1615 /* Handler for menu option */
1617 modest_msg_view_window_show_isearch_toolbar (GtkWidget *obj,
1620 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1621 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1623 gtk_widget_show (priv->isearch_toolbar);
1624 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1627 /* Handler for click on the "X" close button in isearch toolbar */
1629 modest_msg_view_window_isearch_toolbar_close (GtkWidget *widget,
1630 ModestMsgViewWindow *obj)
1632 ModestMsgViewWindowPrivate *priv;
1634 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1637 gtk_widget_hide (priv->isearch_toolbar);
1638 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1642 modest_msg_view_window_isearch_toolbar_search (GtkWidget *widget,
1643 ModestMsgViewWindow *obj)
1645 const gchar *current_search;
1646 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1648 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1649 modest_platform_system_banner (NULL, NULL, _("mail_ib_nothing_to_find"));
1653 current_search = modest_isearch_toolbar_get_search (MODEST_ISEARCH_TOOLBAR (widget));
1655 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1656 modest_platform_system_banner (NULL, NULL, _CS_FIND_REP_ENTER_TEXT);
1660 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1662 g_free (priv->last_search);
1663 priv->last_search = g_strdup (current_search);
1664 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1667 modest_platform_system_banner (NULL, NULL,
1668 _HL_IB_FIND_NO_MATCHES);
1669 g_free (priv->last_search);
1670 priv->last_search = NULL;
1672 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1675 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1676 modest_platform_system_banner (NULL, NULL,
1677 _HL_IB_FIND_COMPLETE);
1678 g_free (priv->last_search);
1679 priv->last_search = NULL;
1681 modest_isearch_toolbar_highlight_entry (MODEST_ISEARCH_TOOLBAR (priv->isearch_toolbar), TRUE);
1688 modest_msg_view_window_set_zoom (ModestWindow *window,
1691 ModestMsgViewWindowPrivate *priv;
1692 ModestWindowPrivate *parent_priv;
1694 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1696 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1697 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1698 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1703 modest_msg_view_window_get_zoom (ModestWindow *window)
1705 ModestMsgViewWindowPrivate *priv;
1707 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1709 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1710 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1714 modest_msg_view_window_zoom_plus (ModestWindow *window)
1717 ModestMsgViewWindowPrivate *priv;
1721 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1722 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1724 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1726 if (zoom_level >= 2.0) {
1727 modest_platform_system_banner (NULL, NULL,
1728 _CS_MAX_ZOOM_LEVEL_REACHED);
1730 } else if (zoom_level >= 1.5) {
1732 } else if (zoom_level >= 1.2) {
1734 } else if (zoom_level >= 1.0) {
1736 } else if (zoom_level >= 0.8) {
1738 } else if (zoom_level >= 0.5) {
1744 /* set zoom level */
1745 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1746 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1747 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1748 g_free (banner_text);
1749 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1755 modest_msg_view_window_zoom_minus (ModestWindow *window)
1758 ModestMsgViewWindowPrivate *priv;
1762 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1763 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1765 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1767 if (zoom_level <= 0.5) {
1768 modest_platform_system_banner (NULL, NULL,
1769 _CS_MIN_ZOOM_LEVEL_REACHED);
1771 } else if (zoom_level <= 0.8) {
1773 } else if (zoom_level <= 1.0) {
1775 } else if (zoom_level <= 1.2) {
1777 } else if (zoom_level <= 1.5) {
1779 } else if (zoom_level <= 2.0) {
1785 /* set zoom level */
1786 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1787 banner_text = g_strdup_printf (_HL_IB_ZOOM, int_zoom);
1788 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1789 g_free (banner_text);
1790 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1796 modest_msg_view_window_key_event (GtkWidget *window,
1802 focus = gtk_container_get_focus_child ((GtkContainer *) window);
1804 /* for the isearch toolbar case */
1805 if (focus && GTK_IS_ENTRY (focus)) {
1806 if (event->keyval == GDK_BackSpace) {
1808 copy = gdk_event_copy ((GdkEvent *) event);
1809 gtk_widget_event (focus, copy);
1810 gdk_event_free (copy);
1820 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1823 ModestMsgViewWindowPrivate *priv;
1824 GtkTreeIter tmp_iter;
1825 gboolean is_last_selected;
1827 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1828 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1830 /*if no model (so no rows at all), then virtually we are the last*/
1831 if (!priv->header_model || !priv->row_reference)
1834 if (!gtk_tree_row_reference_valid (priv->row_reference))
1837 path = gtk_tree_row_reference_get_path (priv->row_reference);
1841 is_last_selected = TRUE;
1842 while (is_last_selected) {
1844 gtk_tree_path_next (path);
1845 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1847 gtk_tree_model_get (priv->header_model, &tmp_iter,
1848 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1851 if (msg_is_visible (header, priv->is_outbox))
1852 is_last_selected = FALSE;
1853 g_object_unref(G_OBJECT(header));
1856 gtk_tree_path_free (path);
1857 return is_last_selected;
1861 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1863 ModestMsgViewWindowPrivate *priv;
1865 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1866 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1868 return priv->header_model != NULL;
1872 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1874 ModestMsgViewWindowPrivate *priv;
1876 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1877 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1879 return priv->is_search_result;
1883 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1885 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1887 if (!check_outbox) {
1890 ModestTnySendQueueStatus status;
1891 status = modest_tny_all_send_queues_get_msg_status (header);
1892 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1893 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1898 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1901 ModestMsgViewWindowPrivate *priv;
1902 gboolean is_first_selected;
1903 GtkTreeIter tmp_iter;
1905 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1906 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1908 /*if no model (so no rows at all), then virtually we are the first*/
1909 if (!priv->header_model || !priv->row_reference)
1912 if (!gtk_tree_row_reference_valid (priv->row_reference))
1915 path = gtk_tree_row_reference_get_path (priv->row_reference);
1919 is_first_selected = TRUE;
1920 while (is_first_selected) {
1922 if(!gtk_tree_path_prev (path))
1924 /* Here the 'if' is needless for logic, but let make sure
1925 * iter is valid for gtk_tree_model_get. */
1926 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1928 gtk_tree_model_get (priv->header_model, &tmp_iter,
1929 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1932 if (msg_is_visible (header, priv->is_outbox))
1933 is_first_selected = FALSE;
1934 g_object_unref(G_OBJECT(header));
1937 gtk_tree_path_free (path);
1938 return is_first_selected;
1945 GtkTreeRowReference *row_reference;
1949 message_reader_performer (gboolean canceled,
1951 ModestWindow *parent_window,
1952 TnyAccount *account,
1955 ModestMailOperation *mail_op = NULL;
1956 MsgReaderInfo *info;
1958 info = (MsgReaderInfo *) user_data;
1959 if (canceled || err) {
1960 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1961 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (parent_window));
1965 /* Register the header - it'll be unregistered in the callback */
1967 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1969 /* New mail operation */
1970 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1971 modest_ui_actions_disk_operations_error_handler,
1974 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1976 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1978 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1979 g_object_unref (mail_op);
1981 /* Update dimming rules */
1982 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1983 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1986 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1987 g_free (info->msg_uid);
1989 g_object_unref (info->folder);
1991 g_object_unref (info->header);
1992 g_slice_free (MsgReaderInfo, info);
1997 * Reads the message whose summary item is @header. It takes care of
1998 * several things, among others:
2000 * If the message was not previously downloaded then ask the user
2001 * before downloading. If there is no connection launch the connection
2002 * dialog. Update toolbar dimming rules.
2004 * Returns: TRUE if the mail operation was started, otherwise if the
2005 * user do not want to download the message, or if the user do not
2006 * want to connect, then the operation is not issued
2009 message_reader (ModestMsgViewWindow *window,
2010 ModestMsgViewWindowPrivate *priv,
2012 const gchar *msg_uid,
2014 GtkTreeRowReference *row_reference)
2016 ModestWindowMgr *mgr;
2017 TnyAccount *account = NULL;
2018 MsgReaderInfo *info;
2020 /* We set the header from model while we're loading */
2021 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
2022 modest_window_set_title (MODEST_WINDOW (window), _CS_UPDATING);
2028 g_object_ref (folder);
2030 mgr = modest_runtime_get_window_mgr ();
2031 /* Msg download completed */
2032 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
2034 /* Ask the user if he wants to download the message if
2036 if (!tny_device_is_online (modest_runtime_get_device())) {
2037 GtkResponseType response;
2038 GtkWindow *toplevel;
2040 toplevel = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) window);
2041 response = modest_platform_run_confirmation_dialog (toplevel, _("mcen_nc_get_msg"));
2042 if (response == GTK_RESPONSE_CANCEL) {
2043 update_window_title (window);
2048 folder = tny_header_get_folder (header);
2050 info = g_slice_new (MsgReaderInfo);
2051 info->msg_uid = g_strdup (msg_uid);
2053 info->header = g_object_ref (header);
2055 info->header = NULL;
2057 info->folder = g_object_ref (folder);
2059 info->folder = NULL;
2060 if (row_reference) {
2061 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2063 info->row_reference = NULL;
2066 /* Offer the connection dialog if necessary */
2067 modest_platform_connect_if_remote_and_perform ((ModestWindow *) window,
2069 TNY_FOLDER_STORE (folder),
2070 message_reader_performer,
2073 g_object_unref (folder);
2079 folder = tny_header_get_folder (header);
2082 account = tny_folder_get_account (folder);
2084 info = g_slice_new (MsgReaderInfo);
2085 info->msg_uid = g_strdup (msg_uid);
2087 info->folder = g_object_ref (folder);
2089 info->folder = NULL;
2091 info->header = g_object_ref (header);
2093 info->header = NULL;
2095 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2097 info->row_reference = NULL;
2099 message_reader_performer (FALSE, NULL, (ModestWindow *) window, account, info);
2101 g_object_unref (account);
2103 g_object_unref (folder);
2109 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2111 ModestMsgViewWindowPrivate *priv;
2112 GtkTreePath *path= NULL;
2113 GtkTreeIter tmp_iter;
2115 gboolean retval = TRUE;
2116 GtkTreeRowReference *row_reference = NULL;
2118 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2119 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2121 if (!priv->row_reference)
2124 /* Update the next row reference if it's not valid. This could
2125 happen if for example the header which it was pointing to,
2126 was deleted. The best place to do it is in the row-deleted
2127 handler but the tinymail model do not work like the glib
2128 tree models and reports the deletion when the row is still
2130 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2131 if (priv->next_row_reference) {
2132 gtk_tree_row_reference_free (priv->next_row_reference);
2134 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2135 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2136 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2138 priv->next_row_reference = NULL;
2141 if (priv->next_row_reference)
2142 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2146 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2148 gtk_tree_model_get_iter (priv->header_model,
2151 gtk_tree_path_free (path);
2153 gtk_tree_model_get (priv->header_model, &tmp_iter,
2154 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2157 /* Read the message & show it */
2158 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2161 gtk_tree_row_reference_free (row_reference);
2164 g_object_unref (header);
2170 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2172 ModestMsgViewWindowPrivate *priv = NULL;
2174 gboolean finished = FALSE;
2175 gboolean retval = FALSE;
2177 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2178 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2180 if (priv->row_reference && !gtk_tree_row_reference_valid (priv->row_reference)) {
2181 gtk_tree_row_reference_free (priv->row_reference);
2182 priv->row_reference = NULL;
2185 /* Return inmediatly if there is no header model */
2186 if (!priv->header_model || !priv->row_reference)
2189 path = gtk_tree_row_reference_get_path (priv->row_reference);
2190 while (!finished && gtk_tree_path_prev (path)) {
2194 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2195 gtk_tree_model_get (priv->header_model, &iter,
2196 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2200 if (msg_is_visible (header, priv->is_outbox)) {
2201 GtkTreeRowReference *row_reference;
2202 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2203 /* Read the message & show it */
2204 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2205 gtk_tree_row_reference_free (row_reference);
2209 g_object_unref (header);
2213 gtk_tree_path_free (path);
2218 view_msg_cb (ModestMailOperation *mail_op,
2225 ModestMsgViewWindow *self = NULL;
2226 ModestMsgViewWindowPrivate *priv = NULL;
2227 GtkTreeRowReference *row_reference = NULL;
2229 /* Unregister the header (it was registered before creating the mail operation) */
2230 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2232 row_reference = (GtkTreeRowReference *) user_data;
2235 gtk_tree_row_reference_free (row_reference);
2236 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2238 /* Restore window title */
2239 update_window_title (self);
2240 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2241 g_object_unref (self);
2246 /* If there was any error */
2247 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2249 gtk_tree_row_reference_free (row_reference);
2250 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2252 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2253 /* First we check if the parent is a folder window */
2254 if (priv->msg_uid && !modest_window_mgr_get_folder_window (MODEST_WINDOW_MGR (modest_runtime_get_window_mgr ()))) {
2256 TnyAccount *account = NULL;
2257 GtkWidget *header_window = NULL;
2259 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2261 /* Get the account */
2263 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2266 if (is_merge || account) {
2267 TnyFolder *folder = NULL;
2269 /* Try to get the message, if it's already downloaded
2270 we don't need to connect */
2272 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account),
2275 ModestTnyAccountStore *account_store;
2276 ModestTnyLocalFoldersAccount *local_folders_account;
2278 account_store = modest_runtime_get_account_store ();
2279 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
2280 modest_tny_account_store_get_local_folders_account (account_store));
2281 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
2282 g_object_unref (local_folders_account);
2284 if (account) g_object_unref (account);
2287 header_window = (GtkWidget *)
2288 modest_header_window_new (
2290 modest_window_get_active_account (MODEST_WINDOW (self)),
2291 modest_window_get_active_mailbox (MODEST_WINDOW (self)));
2292 if (!modest_window_mgr_register_window (modest_runtime_get_window_mgr (),
2293 MODEST_WINDOW (header_window),
2295 gtk_widget_destroy (GTK_WIDGET (header_window));
2297 gtk_widget_show_all (GTK_WIDGET (header_window));
2299 g_object_unref (folder);
2305 /* Restore window title */
2306 update_window_title (self);
2307 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (self));
2308 g_object_unref (self);
2313 /* Get the window */
2314 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2315 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2316 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2318 /* Update the row reference */
2319 if (priv->row_reference != NULL) {
2320 gtk_tree_row_reference_free (priv->row_reference);
2321 priv->row_reference = (row_reference && gtk_tree_row_reference_valid (row_reference))?gtk_tree_row_reference_copy (row_reference):NULL;
2322 if (priv->next_row_reference != NULL) {
2323 gtk_tree_row_reference_free (priv->next_row_reference);
2325 if (priv->row_reference) {
2326 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2327 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2329 priv->next_row_reference = NULL;
2333 /* Mark header as read */
2334 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN)) {
2337 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2338 uid = modest_tny_folder_get_header_unique_id (header);
2339 modest_platform_emit_msg_read_changed_signal (uid, TRUE);
2343 /* Set new message */
2344 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2345 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2346 modest_msg_view_window_update_priority (self);
2347 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2348 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2349 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2352 /* Set the new message uid of the window */
2353 if (priv->msg_uid) {
2354 g_free (priv->msg_uid);
2355 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2358 /* Notify the observers */
2359 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2360 0, priv->header_model, priv->row_reference);
2362 /* Sync the flags if the message is not opened from a header
2363 model, i.e, if it's opened from a notification */
2364 if (!priv->header_model)
2368 g_object_unref (self);
2370 gtk_tree_row_reference_free (row_reference);
2374 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2376 ModestMsgViewWindowPrivate *priv;
2378 TnyFolderType folder_type;
2380 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2382 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2384 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2388 folder = tny_msg_get_folder (msg);
2390 folder_type = modest_tny_folder_guess_folder_type (folder);
2391 g_object_unref (folder);
2393 g_object_unref (msg);
2401 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2403 ModestMsgViewWindowPrivate *priv;
2404 TnyHeader *header = NULL;
2405 TnyHeaderFlags flags = 0;
2407 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2409 if (priv->header_model && priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
2411 GtkTreePath *path = NULL;
2413 path = gtk_tree_row_reference_get_path (priv->row_reference);
2414 g_return_if_fail (path != NULL);
2415 gtk_tree_model_get_iter (priv->header_model,
2417 gtk_tree_row_reference_get_path (priv->row_reference));
2419 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2421 gtk_tree_path_free (path);
2424 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2426 header = tny_msg_get_header (msg);
2427 g_object_unref (msg);
2432 flags = tny_header_get_flags (header);
2433 g_object_unref(G_OBJECT(header));
2436 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2441 toolbar_resize (ModestMsgViewWindow *self)
2443 ModestMsgViewWindowPrivate *priv = NULL;
2444 ModestWindowPrivate *parent_priv = NULL;
2446 gint static_button_size;
2447 ModestWindowMgr *mgr;
2449 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2450 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2451 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2453 mgr = modest_runtime_get_window_mgr ();
2454 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2456 if (parent_priv->toolbar) {
2457 /* Set expandable and homogeneous tool buttons */
2458 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2459 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2460 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2461 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReplyAll");
2462 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2463 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2464 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageForward");
2465 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2466 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2467 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2468 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2469 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2470 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDownloadExternalImages");
2471 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
2472 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
2473 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2474 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2475 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2476 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2481 modest_msg_view_window_show_toolbar (ModestWindow *self,
2482 gboolean show_toolbar)
2484 ModestMsgViewWindowPrivate *priv = NULL;
2485 ModestWindowPrivate *parent_priv;
2487 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2488 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2490 /* Set optimized view status */
2491 priv->optimized_view = !show_toolbar;
2493 if (!parent_priv->toolbar) {
2494 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2497 #ifdef MODEST_TOOLKIT_HILDON2
2498 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2500 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), GTK_ICON_SIZE_LARGE_TOOLBAR);
2502 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2504 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2505 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2506 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2508 modest_window_add_toolbar (MODEST_WINDOW (self),
2509 GTK_TOOLBAR (parent_priv->toolbar));
2514 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2515 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2516 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2518 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2519 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2520 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2522 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2525 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2526 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2531 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2533 ModestMsgViewWindow *window)
2535 if (!GTK_WIDGET_VISIBLE (window))
2538 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2542 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2544 ModestMsgViewWindowPrivate *priv;
2546 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2547 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2549 return priv->progress_hint;
2553 observers_empty (ModestMsgViewWindow *self)
2556 ModestMsgViewWindowPrivate *priv;
2557 gboolean is_empty = TRUE;
2558 guint pending_ops = 0;
2560 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2561 tmp = priv->progress_widgets;
2563 /* Check all observers */
2564 while (tmp && is_empty) {
2565 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2566 is_empty = pending_ops == 0;
2568 tmp = g_slist_next(tmp);
2575 on_account_removed (TnyAccountStore *account_store,
2576 TnyAccount *account,
2579 /* Do nothing if it's a transport account, because we only
2580 show the messages of a store account */
2581 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2582 const gchar *parent_acc = NULL;
2583 const gchar *our_acc = NULL;
2585 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2586 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2588 /* Close this window if I'm showing a message of the removed account */
2589 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2590 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2595 on_mail_operation_started (ModestMailOperation *mail_op,
2598 ModestMsgViewWindow *self;
2599 ModestMailOperationTypeOperation op_type;
2601 ModestMsgViewWindowPrivate *priv;
2602 GObject *source = NULL;
2604 self = MODEST_MSG_VIEW_WINDOW (user_data);
2605 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2606 op_type = modest_mail_operation_get_type_operation (mail_op);
2607 tmp = priv->progress_widgets;
2608 source = modest_mail_operation_get_source(mail_op);
2609 if (G_OBJECT (self) == source) {
2610 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2611 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2612 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2613 set_progress_hint (self, TRUE);
2615 modest_progress_object_add_operation (
2616 MODEST_PROGRESS_OBJECT (tmp->data),
2618 tmp = g_slist_next (tmp);
2622 g_object_unref (source);
2624 /* Update dimming rules */
2625 check_dimming_rules_after_change (self);
2629 on_mail_operation_finished (ModestMailOperation *mail_op,
2632 ModestMsgViewWindow *self;
2633 ModestMailOperationTypeOperation op_type;
2635 ModestMsgViewWindowPrivate *priv;
2637 self = MODEST_MSG_VIEW_WINDOW (user_data);
2638 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2639 op_type = modest_mail_operation_get_type_operation (mail_op);
2640 tmp = priv->progress_widgets;
2642 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ||
2643 op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ||
2644 op_type == MODEST_MAIL_OPERATION_TYPE_DELETE) {
2646 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2648 tmp = g_slist_next (tmp);
2651 /* If no more operations are being observed, NORMAL mode is enabled again */
2652 if (observers_empty (self)) {
2653 set_progress_hint (self, FALSE);
2657 /* Update dimming rules. We have to do this right here
2658 and not in view_msg_cb because at that point the
2659 transfer mode is still enabled so the dimming rule
2660 won't let the user delete the message that has been
2661 readed for example */
2662 check_dimming_rules_after_change (self);
2666 on_queue_changed (ModestMailOperationQueue *queue,
2667 ModestMailOperation *mail_op,
2668 ModestMailOperationQueueNotification type,
2669 ModestMsgViewWindow *self)
2671 ModestMsgViewWindowPrivate *priv;
2673 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2675 /* If this operations was created by another window, do nothing */
2676 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2679 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2680 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2682 "operation-started",
2683 G_CALLBACK (on_mail_operation_started),
2685 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2687 "operation-finished",
2688 G_CALLBACK (on_mail_operation_finished),
2690 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2691 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2693 "operation-started");
2694 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2696 "operation-finished");
2701 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2703 ModestMsgViewWindowPrivate *priv;
2704 TnyList *selected_attachments = NULL;
2706 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2707 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2709 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2710 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2712 return selected_attachments;
2716 ModestMsgViewWindow *self;
2718 gchar *attachment_uid;
2719 } DecodeAsyncHelper;
2722 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2728 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2729 const gchar *content_type;
2730 ModestMsgViewWindowPrivate *priv;
2732 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (helper->self);
2734 if (cancelled || err) {
2737 if ((err->domain == TNY_ERROR_DOMAIN) &&
2738 (err->code == TNY_IO_ERROR_WRITE) &&
2739 (errno == ENOSPC)) {
2740 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2742 msg = g_strdup (_("mail_ib_file_operation_failed"));
2744 modest_platform_information_banner (NULL, NULL, msg);
2750 /* It could happen that the window was closed. So we
2751 assume it is a cancelation */
2752 if (!GTK_WIDGET_VISIBLE (helper->self))
2755 /* Remove the progress hint */
2756 set_progress_hint (helper->self, FALSE);
2758 content_type = tny_mime_part_get_content_type (mime_part);
2759 if (content_type && g_str_has_prefix (content_type, "message/rfc822")) {
2760 ModestWindowMgr *mgr;
2761 ModestWindow *msg_win = NULL;
2764 const gchar *mailbox;
2765 TnyStream *file_stream;
2768 fd = g_open (helper->file_path, O_RDONLY, 0644);
2771 file_stream = tny_fs_stream_new (fd);
2773 mgr = modest_runtime_get_window_mgr ();
2775 account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (helper->self)));
2776 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (helper->self));
2779 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2781 msg = tny_camel_msg_new ();
2782 tny_camel_msg_parse (TNY_CAMEL_MSG (msg), file_stream);
2785 top_msg = g_object_ref (priv->top_msg);
2787 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2789 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (msg), top_msg,
2790 account, mailbox, helper->attachment_uid);
2791 if (top_msg) g_object_unref (top_msg);
2792 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2793 modest_window_get_zoom (MODEST_WINDOW (helper->self)));
2794 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (helper->self)))
2795 gtk_widget_show_all (GTK_WIDGET (msg_win));
2797 gtk_widget_destroy (GTK_WIDGET (msg_win));
2798 g_object_unref (msg);
2799 g_object_unref (file_stream);
2801 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2806 /* make the file read-only */
2807 g_chmod(helper->file_path, 0444);
2809 /* Activate the file */
2810 modest_platform_activate_file (helper->file_path, content_type);
2815 g_object_unref (helper->self);
2816 g_free (helper->file_path);
2817 g_free (helper->attachment_uid);
2818 g_slice_free (DecodeAsyncHelper, helper);
2822 view_attachment_connect_handler (gboolean canceled,
2824 GtkWindow *parent_window,
2825 TnyAccount *account,
2829 if (canceled || err) {
2830 g_object_unref (part);
2834 modest_msg_view_window_view_attachment (MODEST_MSG_VIEW_WINDOW (parent_window),
2836 g_object_unref (part);
2840 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2841 TnyMimePart *mime_part)
2843 ModestMsgViewWindowPrivate *priv;
2844 const gchar *msg_uid;
2845 gchar *attachment_uid = NULL;
2846 gint attachment_index = 0;
2847 TnyList *attachments;
2849 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2850 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2851 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2853 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2854 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2855 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2856 g_object_unref (attachments);
2858 if (msg_uid && attachment_index >= 0) {
2859 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2862 if (mime_part == NULL) {
2863 gboolean error = FALSE;
2864 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2865 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2867 } else if (tny_list_get_length (selected_attachments) > 1) {
2868 modest_platform_system_banner (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2872 iter = tny_list_create_iterator (selected_attachments);
2873 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2874 g_object_unref (iter);
2876 if (selected_attachments)
2877 g_object_unref (selected_attachments);
2882 g_object_ref (mime_part);
2885 if (tny_mime_part_is_purged (mime_part))
2888 if (TNY_IS_CAMEL_BS_MIME_PART (mime_part) &&
2889 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (mime_part))) {
2891 TnyAccount *account;
2893 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
2895 /* Get the account */
2897 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
2900 if (!tny_device_is_online (modest_runtime_get_device())) {
2901 modest_platform_connect_and_perform ((ModestWindow *) window,
2903 TNY_ACCOUNT (account),
2904 (ModestConnectedPerformer) view_attachment_connect_handler,
2905 g_object_ref (mime_part));
2910 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2911 gchar *filepath = NULL;
2912 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2913 gboolean show_error_banner = FALSE;
2914 TnyFsStream *temp_stream = NULL;
2915 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2918 if (temp_stream != NULL) {
2919 ModestAccountMgr *mgr;
2920 DecodeAsyncHelper *helper;
2921 gboolean decode_in_provider;
2922 ModestProtocol *protocol;
2923 const gchar *account;
2925 /* Activate progress hint */
2926 set_progress_hint (window, TRUE);
2928 helper = g_slice_new0 (DecodeAsyncHelper);
2929 helper->self = g_object_ref (window);
2930 helper->file_path = g_strdup (filepath);
2931 helper->attachment_uid = g_strdup (attachment_uid);
2933 decode_in_provider = FALSE;
2934 mgr = modest_runtime_get_account_mgr ();
2935 account = modest_window_get_active_account (MODEST_WINDOW (window));
2936 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
2937 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
2939 uri = g_strconcat ("file://", filepath, NULL);
2940 decode_in_provider =
2941 modest_account_protocol_decode_part_to_stream_async (
2942 MODEST_ACCOUNT_PROTOCOL (protocol),
2945 TNY_STREAM (temp_stream),
2946 on_decode_to_stream_async_handler,
2953 if (!decode_in_provider)
2954 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2955 on_decode_to_stream_async_handler,
2958 g_object_unref (temp_stream);
2959 /* NOTE: files in the temporary area will be automatically
2960 * cleaned after some time if they are no longer in use */
2963 const gchar *content_type;
2964 /* the file may already exist but it isn't writable,
2965 * let's try to open it anyway */
2966 content_type = tny_mime_part_get_content_type (mime_part);
2967 modest_platform_activate_file (filepath, content_type);
2969 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2970 show_error_banner = TRUE;
2975 if (show_error_banner)
2976 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2977 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2978 ModestWindowMgr *mgr;
2979 ModestWindow *msg_win = NULL;
2980 TnyMsg *current_msg;
2984 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2985 mgr = modest_runtime_get_window_mgr ();
2986 header = tny_msg_get_header (TNY_MSG (current_msg));
2987 found = modest_window_mgr_find_registered_message_uid (mgr,
2992 g_debug ("window for this body is already being created");
2996 /* it's not found, so create a new window for it */
2997 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2998 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2999 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3001 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3004 top_msg = g_object_ref (priv->top_msg);
3006 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3008 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part), top_msg,
3009 account, mailbox, attachment_uid);
3011 if (top_msg) g_object_unref (top_msg);
3013 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3014 modest_window_get_zoom (MODEST_WINDOW (window)));
3015 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3016 gtk_widget_show_all (GTK_WIDGET (msg_win));
3018 gtk_widget_destroy (GTK_WIDGET (msg_win));
3020 g_object_unref (current_msg);
3022 /* message attachment */
3023 TnyHeader *header = NULL;
3024 ModestWindowMgr *mgr;
3025 ModestWindow *msg_win = NULL;
3028 header = tny_msg_get_header (TNY_MSG (mime_part));
3029 mgr = modest_runtime_get_window_mgr ();
3030 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
3033 /* if it's found, but there is no msg_win, it's probably in the process of being created;
3034 * thus, we don't do anything */
3035 g_debug ("window for is already being created");
3038 /* it's not found, so create a new window for it */
3039 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
3040 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
3041 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
3043 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
3045 top_msg = g_object_ref (priv->top_msg);
3047 top_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3048 msg_win = modest_msg_view_window_new_for_attachment (
3049 TNY_MSG (mime_part), top_msg, account,
3050 mailbox, attachment_uid);
3051 modest_window_set_zoom (MODEST_WINDOW (msg_win),
3052 modest_window_get_zoom (MODEST_WINDOW (window)));
3053 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
3054 gtk_widget_show_all (GTK_WIDGET (msg_win));
3056 gtk_widget_destroy (GTK_WIDGET (msg_win));
3062 g_free (attachment_uid);
3064 g_object_unref (mime_part);
3076 GnomeVFSResult result;
3078 ModestMsgViewWindow *window;
3081 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
3082 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
3083 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
3084 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
3087 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
3091 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
3092 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
3093 g_free (pair->filename);
3094 g_object_unref (pair->part);
3095 g_slice_free (SaveMimePartPair, pair);
3097 g_list_free (info->pairs);
3100 g_object_unref (info->window);
3101 info->window = NULL;
3103 g_slice_free (SaveMimePartInfo, info);
3108 idle_save_mime_part_show_result (SaveMimePartInfo *info)
3110 /* This is a GDK lock because we are an idle callback and
3111 * modest_platform_system_banner is or does Gtk+ code */
3113 gdk_threads_enter (); /* CHECKED */
3114 if (info->result == GNOME_VFS_ERROR_CANCELLED) {
3116 } else if (info->result == GNOME_VFS_OK) {
3117 modest_platform_system_banner (NULL, NULL, _CS_SAVED);
3118 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
3121 /* Check if the uri belongs to the external mmc */
3122 if (g_str_has_prefix (info->uri, g_getenv (MODEST_MMC1_VOLUMEPATH_ENV)))
3123 msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
3125 msg = g_strdup (_KR("cerm_memory_card_full"));
3126 modest_platform_information_banner (NULL, NULL, msg);
3129 modest_platform_system_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
3131 set_progress_hint (info->window, FALSE);
3132 save_mime_part_info_free (info, FALSE);
3133 gdk_threads_leave (); /* CHECKED */
3139 save_mime_part_to_file_connect_handler (gboolean canceled,
3141 GtkWindow *parent_window,
3142 TnyAccount *account,
3143 SaveMimePartInfo *info)
3145 if (canceled || err) {
3146 if (canceled && !err) {
3147 info->result = GNOME_VFS_ERROR_CANCELLED;
3149 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3151 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3156 save_mime_part_to_file_connect_idle (SaveMimePartInfo *info)
3159 TnyAccount *account;
3160 ModestMsgViewWindowPrivate *priv;
3162 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3164 is_merge = g_str_has_prefix (priv->msg_uid, "merge:");
3167 /* Get the account */
3169 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
3172 modest_platform_connect_and_perform ((ModestWindow *) info->window,
3174 TNY_ACCOUNT (account),
3175 (ModestConnectedPerformer) save_mime_part_to_file_connect_handler,
3179 g_object_unref (account);
3185 save_mime_part_to_file (SaveMimePartInfo *info)
3187 GnomeVFSHandle *handle;
3189 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
3191 if (TNY_IS_CAMEL_BS_MIME_PART (pair->part) &&
3192 !tny_camel_bs_mime_part_is_fetched (TNY_CAMEL_BS_MIME_PART (pair->part))) {
3193 gboolean check_online = TRUE;
3194 ModestMsgViewWindowPrivate *priv = NULL;
3196 /* Check if we really need to connect to save the mime part */
3197 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (info->window);
3198 if (g_str_has_prefix (priv->msg_uid, "merge:")) {
3199 check_online = FALSE;
3201 TnyAccountStore *acc_store;
3202 TnyAccount *account = NULL;
3204 acc_store = (TnyAccountStore*) modest_runtime_get_account_store ();
3205 account = tny_account_store_find_account (acc_store, priv->msg_uid);
3208 if (tny_account_get_connection_status (account) ==
3209 TNY_CONNECTION_STATUS_CONNECTED)
3210 check_online = FALSE;
3211 g_object_unref (account);
3213 check_online = !tny_device_is_online (tny_account_store_get_device (acc_store));
3218 g_idle_add ((GSourceFunc) save_mime_part_to_file_connect_idle, info);
3223 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
3224 if (info->result == GNOME_VFS_OK) {
3225 GError *error = NULL;
3226 gboolean decode_in_provider;
3228 ModestAccountMgr *mgr;
3229 const gchar *account;
3230 ModestProtocol *protocol = NULL;
3232 stream = tny_vfs_stream_new (handle);
3234 decode_in_provider = FALSE;
3235 mgr = modest_runtime_get_account_mgr ();
3236 account = modest_window_get_active_account (MODEST_WINDOW (info->window));
3237 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3238 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3239 decode_in_provider =
3240 modest_account_protocol_decode_part_to_stream (
3241 MODEST_ACCOUNT_PROTOCOL (protocol),
3249 if (!decode_in_provider)
3250 written = tny_mime_part_decode_to_stream (pair->part, stream, &error);
3253 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
3255 if (error && (error->domain == TNY_ERROR_DOMAIN) &&
3256 (error->code == TNY_IO_ERROR_WRITE) &&
3257 (errno == ENOSPC)) {
3258 info->result = GNOME_VFS_ERROR_NO_SPACE;
3260 info->result = GNOME_VFS_ERROR_IO;
3263 g_object_unref (G_OBJECT (stream));
3265 g_warning ("Could not create save attachment %s: %s\n",
3266 pair->filename, gnome_vfs_result_to_string (info->result));
3269 /* Go on saving remaining files */
3270 info->pairs = g_list_remove_link (info->pairs, info->pairs);
3271 if (info->pairs != NULL) {
3272 save_mime_part_to_file (info);
3274 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
3281 save_mime_parts_to_file_with_checks (GtkWindow *parent,
3282 SaveMimePartInfo *info)
3284 gboolean is_ok = TRUE;
3285 gint replaced_files = 0;
3286 const GList *files = info->pairs;
3287 const GList *iter, *to_replace = NULL;
3289 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
3290 SaveMimePartPair *pair = iter->data;
3291 gchar *unescaped = g_uri_unescape_string (pair->filename, NULL);
3293 if (modest_utils_file_exists (unescaped)) {
3295 if (replaced_files == 1)
3300 if (replaced_files) {
3303 if (replaced_files == 1) {
3304 SaveMimePartPair *pair = to_replace->data;
3305 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
3306 gchar *escaped_basename, *message;
3308 escaped_basename = g_uri_unescape_string (basename, NULL);
3309 message = g_strdup_printf ("%s\n%s",
3311 (escaped_basename) ? escaped_basename : "");
3312 response = modest_platform_run_confirmation_dialog (parent, message);
3314 g_free (escaped_basename);
3316 response = modest_platform_run_confirmation_dialog (parent,
3317 _FM_REPLACE_MULTIPLE);
3319 if (response != GTK_RESPONSE_OK)
3324 save_mime_part_info_free (info, TRUE);
3326 /* Start progress and launch thread */
3327 set_progress_hint (info->window, TRUE);
3328 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
3333 typedef struct _SaveAttachmentsInfo {
3334 TnyList *attachments_list;
3335 ModestMsgViewWindow *window;
3336 } SaveAttachmentsInfo;
3339 save_attachments_response (GtkDialog *dialog,
3343 TnyList *mime_parts;
3345 GList *files_to_save = NULL;
3346 gchar *current_folder;
3347 SaveAttachmentsInfo *sa_info = (SaveAttachmentsInfo *) user_data;
3349 mime_parts = TNY_LIST (sa_info->attachments_list);
3351 if (arg1 != GTK_RESPONSE_OK)
3354 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
3355 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
3356 if (current_folder && *current_folder != '\0') {
3358 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
3359 current_folder,&err);
3361 g_debug ("Error storing latest used folder: %s", err->message);
3365 g_free (current_folder);
3367 if (!modest_utils_folder_writable (chooser_uri)) {
3368 const gchar *err_msg;
3370 #ifdef MODEST_PLATFORM_MAEMO
3371 if (modest_maemo_utils_in_usb_mode ()) {
3372 err_msg = dgettext ("hildon-status-bar-usb", "usbh_ib_mmc_usb_connected");
3374 err_msg = _FM_READ_ONLY_LOCATION;
3377 err_msg = _FM_READ_ONLY_LOCATION;
3379 modest_platform_system_banner (NULL, NULL, err_msg);
3383 iter = tny_list_create_iterator (mime_parts);
3384 while (!tny_iterator_is_done (iter)) {
3385 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3387 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
3388 !tny_mime_part_is_purged (mime_part) &&
3389 (tny_mime_part_get_filename (mime_part) != NULL)) {
3390 SaveMimePartPair *pair;
3392 pair = g_slice_new0 (SaveMimePartPair);
3394 if (tny_list_get_length (mime_parts) > 1) {
3396 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
3397 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
3400 pair->filename = g_strdup (chooser_uri);
3402 pair->part = mime_part;
3403 files_to_save = g_list_prepend (files_to_save, pair);
3405 tny_iterator_next (iter);
3407 g_object_unref (iter);
3410 if (files_to_save != NULL) {
3411 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
3412 info->pairs = files_to_save;
3413 info->result = TRUE;
3414 info->uri = g_strdup (chooser_uri);
3415 info->window = g_object_ref (sa_info->window);
3416 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
3418 g_free (chooser_uri);
3421 /* Free and close the dialog */
3422 g_object_unref (mime_parts);
3423 g_object_unref (sa_info->window);
3424 g_slice_free (SaveAttachmentsInfo, sa_info);
3425 gtk_widget_destroy (GTK_WIDGET (dialog));
3429 msg_is_attachment (TnyList *mime_parts)
3432 gboolean retval = FALSE;
3434 if (tny_list_get_length (mime_parts) > 1)
3437 iter = tny_list_create_iterator (mime_parts);
3439 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3441 if (TNY_IS_MSG (part))
3443 g_object_unref (part);
3445 g_object_unref (iter);
3451 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3452 TnyList *mime_parts)
3454 ModestMsgViewWindowPrivate *priv;
3455 GtkWidget *save_dialog = NULL;
3456 gchar *conf_folder = NULL;
3457 gchar *filename = NULL;
3458 gchar *save_multiple_str = NULL;
3459 const gchar *root_folder = "file:///";
3461 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3462 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3464 if (mime_parts == NULL) {
3465 gboolean allow_msgs = FALSE;
3467 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3468 * selection available */
3469 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3471 /* Check if the message is composed by an unique MIME
3472 part whose content disposition is attachment. There
3473 could be messages like this:
3475 Date: Tue, 12 Jan 2010 20:40:59 +0000
3476 From: <sender@example.org>
3477 To: <recipient@example.org>
3479 Content-Type: image/jpeg
3480 Content-Disposition: attachment; filename="bug7718.jpeg"
3482 whose unique MIME part is the message itself whose
3483 content disposition is attachment
3485 if (mime_parts && msg_is_attachment (mime_parts))
3488 if (mime_parts && !modest_toolkit_utils_select_attachments (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))), mime_parts, allow_msgs)) {
3489 g_object_unref (mime_parts);
3493 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3495 g_object_unref (mime_parts);
3501 g_object_ref (mime_parts);
3504 /* prepare dialog */
3505 if (tny_list_get_length (mime_parts) == 1) {
3507 /* only one attachment selected */
3508 iter = tny_list_create_iterator (mime_parts);
3509 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3510 g_object_unref (iter);
3511 if (!modest_tny_mime_part_is_msg (mime_part) &&
3512 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3513 !tny_mime_part_is_purged (mime_part)) {
3514 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3516 /* TODO: show any error? */
3517 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3518 g_object_unref (mime_parts);
3521 g_object_unref (mime_part);
3523 gint num = tny_list_get_length (mime_parts);
3524 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3525 "sfil_va_number_of_objects_attachment",
3526 "sfil_va_number_of_objects_attachments",
3530 /* Creation of hildon file chooser dialog for saving */
3531 save_dialog = modest_toolkit_factory_create_file_chooser_dialog (modest_runtime_get_toolkit_factory (),
3533 (GtkWindow *) window,
3534 GTK_FILE_CHOOSER_ACTION_SAVE);
3536 /* Get last used folder */
3537 conf_folder = modest_conf_get_string (modest_runtime_get_conf (),
3538 MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3540 /* File chooser stops working if we select "file:///" as current folder */
3541 if (conf_folder && g_ascii_strcasecmp (root_folder, conf_folder) != 0) {
3542 g_free (conf_folder);
3546 if (conf_folder && conf_folder[0] != '\0') {
3547 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3550 /* Set the default folder to documents folder */
3551 docs_folder = (gchar *) g_strdup(g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
3554 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3556 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3557 g_free (docs_folder);
3559 g_free (conf_folder);
3563 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3568 /* if multiple, set multiple string */
3569 if (save_multiple_str) {
3570 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3571 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM_SAVE_OBJECT_FILES);
3572 g_free (save_multiple_str);
3575 /* We must run this asynchronously, because the hildon dialog
3576 performs a gtk_dialog_run by itself which leads to gdk
3578 SaveAttachmentsInfo *sa_info;
3579 sa_info = g_slice_new (SaveAttachmentsInfo);
3580 sa_info->attachments_list = mime_parts;
3581 sa_info->window = g_object_ref (window);
3582 g_signal_connect (save_dialog, "response",
3583 G_CALLBACK (save_attachments_response), sa_info);
3585 gtk_widget_show_all (save_dialog);
3589 show_remove_attachment_information (gpointer userdata)
3591 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3592 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3594 /* We're outside the main lock */
3595 gdk_threads_enter ();
3597 if (priv->remove_attachment_banner != NULL) {
3598 gtk_widget_destroy (priv->remove_attachment_banner);
3599 g_object_unref (priv->remove_attachment_banner);
3602 priv->remove_attachment_banner = g_object_ref (
3603 modest_platform_animation_banner (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3605 gdk_threads_leave ();
3611 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3613 ModestMsgViewWindowPrivate *priv;
3614 TnyList *mime_parts = NULL, *tmp;
3615 gchar *confirmation_message;
3621 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3622 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3624 #ifdef MODEST_TOOLKIT_HILDON2
3625 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3626 * because we don't have selection
3628 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3630 /* Remove already purged messages from mime parts list. We use
3631 a copy of the list to remove items in the original one */
3632 tmp = tny_list_copy (mime_parts);
3633 iter = tny_list_create_iterator (tmp);
3634 while (!tny_iterator_is_done (iter)) {
3635 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3636 if (tny_mime_part_is_purged (part))
3637 tny_list_remove (mime_parts, (GObject *) part);
3639 g_object_unref (part);
3640 tny_iterator_next (iter);
3642 g_object_unref (tmp);
3643 g_object_unref (iter);
3645 if (!modest_toolkit_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3646 tny_list_get_length (mime_parts) == 0) {
3647 g_object_unref (mime_parts);
3651 /* In gtk we get only selected attachments for the operation.
3653 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
3655 /* Remove already purged messages from mime parts list. We use
3656 a copy of the list to remove items in the original one */
3657 tmp = tny_list_copy (mime_parts);
3658 iter = tny_list_create_iterator (tmp);
3659 while (!tny_iterator_is_done (iter)) {
3660 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3661 if (tny_mime_part_is_purged (part))
3662 tny_list_remove (mime_parts, (GObject *) part);
3664 g_object_unref (part);
3665 tny_iterator_next (iter);
3667 g_object_unref (tmp);
3668 g_object_unref (iter);
3670 if (tny_list_get_length (mime_parts) == 0) {
3671 g_object_unref (mime_parts);
3676 n_attachments = tny_list_get_length (mime_parts);
3677 if (n_attachments == 1) {
3681 iter = tny_list_create_iterator (mime_parts);
3682 part = (TnyMimePart *) tny_iterator_get_current (iter);
3683 g_object_unref (iter);
3684 if (modest_tny_mime_part_is_msg (part)) {
3686 header = tny_msg_get_header (TNY_MSG (part));
3687 filename = tny_header_dup_subject (header);
3688 g_object_unref (header);
3689 if (filename == NULL)
3690 filename = g_strdup (_("mail_va_no_subject"));
3692 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3694 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3696 g_object_unref (part);
3698 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3699 "mcen_nc_purge_files_text",
3700 n_attachments), n_attachments);
3702 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (window))),
3703 confirmation_message);
3704 g_free (confirmation_message);
3706 if (response != GTK_RESPONSE_OK) {
3707 g_object_unref (mime_parts);
3711 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3713 iter = tny_list_create_iterator (mime_parts);
3714 while (!tny_iterator_is_done (iter)) {
3717 part = (TnyMimePart *) tny_iterator_get_current (iter);
3718 tny_mime_part_set_purged (TNY_MIME_PART (part));
3719 g_object_unref (part);
3720 tny_iterator_next (iter);
3722 g_object_unref (iter);
3724 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3725 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3726 tny_msg_rewrite_cache (msg);
3727 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3728 g_object_unref (msg);
3729 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3731 g_object_unref (mime_parts);
3733 if (priv->purge_timeout > 0) {
3734 g_source_remove (priv->purge_timeout);
3735 priv->purge_timeout = 0;
3738 if (priv->remove_attachment_banner) {
3739 gtk_widget_destroy (priv->remove_attachment_banner);
3740 g_object_unref (priv->remove_attachment_banner);
3741 priv->remove_attachment_banner = NULL;
3747 update_window_title (ModestMsgViewWindow *window)
3749 ModestMsgViewWindowPrivate *priv;
3751 TnyHeader *header = NULL;
3752 gchar *subject = NULL;
3754 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3756 /* Note that if the window is closed while we're retrieving
3757 the message, this widget could de deleted */
3758 if (!priv->msg_view)
3761 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3763 if (priv->other_body) {
3766 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3768 g_strstrip (description);
3769 subject = description;
3771 } else if (msg != NULL) {
3772 header = tny_msg_get_header (msg);
3773 subject = tny_header_dup_subject (header);
3774 g_object_unref (header);
3775 g_object_unref (msg);
3778 if ((subject == NULL)||(subject[0] == '\0')) {
3780 subject = g_strdup (_("mail_va_no_subject"));
3783 modest_window_set_title (MODEST_WINDOW (window), subject);
3788 on_move_focus (GtkWidget *widget,
3789 GtkDirectionType direction,
3792 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3796 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3798 GnomeVFSResult result;
3799 GnomeVFSHandle *handle = NULL;
3800 GnomeVFSFileInfo *info = NULL;
3803 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3804 if (result != GNOME_VFS_OK) {
3809 info = gnome_vfs_file_info_new ();
3810 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3811 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3812 /* We put a "safe" default size for going to cache */
3813 *expected_size = (300*1024);
3815 *expected_size = info->size;
3817 gnome_vfs_file_info_unref (info);
3819 stream = tny_vfs_stream_new (handle);
3828 TnyStream *output_stream;
3829 GtkWidget *msg_view;
3834 on_fetch_image_timeout_refresh_view (gpointer userdata)
3836 ModestMsgViewWindowPrivate *priv;
3838 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (userdata);
3839 update_progress_hint (MODEST_MSG_VIEW_WINDOW (userdata));
3840 /* Note that priv->msg_view is set to NULL when this window is
3842 if (priv->msg_view && GTK_WIDGET_DRAWABLE (priv->msg_view)) {
3843 gtk_widget_queue_draw (GTK_WIDGET (priv->msg_view));
3845 priv->fetch_image_redraw_handler = 0;
3846 g_object_unref (userdata);
3851 on_fetch_image_idle_refresh_view (gpointer userdata)
3854 FetchImageData *fidata = (FetchImageData *) userdata;
3856 gdk_threads_enter ();
3857 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3858 ModestMsgViewWindowPrivate *priv;
3860 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3861 priv->fetching_images--;
3862 if (priv->fetch_image_redraw_handler == 0) {
3863 priv->fetch_image_redraw_handler = g_timeout_add (500, on_fetch_image_timeout_refresh_view, g_object_ref (fidata->window));
3867 gdk_threads_leave ();
3869 g_object_unref (fidata->msg_view);
3870 g_object_unref (fidata->window);
3871 g_slice_free (FetchImageData, fidata);
3876 on_fetch_image_thread (gpointer userdata)
3878 FetchImageData *fidata = (FetchImageData *) userdata;
3879 TnyStreamCache *cache;
3880 TnyStream *cache_stream;
3882 cache = modest_runtime_get_images_cache ();
3884 tny_stream_cache_get_stream (cache,
3886 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3887 (gpointer) fidata->uri);
3888 g_free (fidata->cache_id);
3889 g_free (fidata->uri);
3891 if (cache_stream != NULL) {
3894 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3897 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3898 if (G_UNLIKELY (nb_read < 0)) {
3900 } else if (G_LIKELY (nb_read > 0)) {
3901 gssize nb_written = 0;
3903 while (G_UNLIKELY (nb_written < nb_read)) {
3906 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3907 nb_read - nb_written);
3908 if (G_UNLIKELY (len < 0))
3914 tny_stream_close (cache_stream);
3915 g_object_unref (cache_stream);
3918 tny_stream_close (fidata->output_stream);
3919 g_object_unref (fidata->output_stream);
3921 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3927 on_fetch_image (ModestMsgView *msgview,
3930 ModestMsgViewWindow *window)
3932 const gchar *current_account;
3933 ModestMsgViewWindowPrivate *priv;
3934 FetchImageData *fidata;
3936 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3938 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3940 fidata = g_slice_new0 (FetchImageData);
3941 fidata->msg_view = g_object_ref (msgview);
3942 fidata->window = g_object_ref (window);
3943 fidata->uri = g_strdup (uri);
3944 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3945 fidata->output_stream = g_object_ref (stream);
3947 priv->fetching_images++;
3948 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3949 g_object_unref (fidata->output_stream);
3950 g_free (fidata->cache_id);
3951 g_free (fidata->uri);
3952 g_object_unref (fidata->msg_view);
3953 g_slice_free (FetchImageData, fidata);
3954 tny_stream_close (stream);
3955 priv->fetching_images--;
3956 update_progress_hint (window);
3959 update_progress_hint (window);
3965 setup_menu (ModestMsgViewWindow *self)
3967 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3969 /* Settings menu buttons */
3970 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_find"), NULL,
3971 MODEST_WINDOW_MENU_CALLBACK (modest_msg_view_window_show_isearch_toolbar),
3972 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_find_in_msg));
3974 modest_window_add_to_menu (MODEST_WINDOW (self),
3975 dngettext(GETTEXT_PACKAGE,
3976 "mcen_me_move_message",
3977 "mcen_me_move_messages",
3980 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_move_to),
3981 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
3983 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3984 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3985 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3987 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3988 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3989 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3991 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3992 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_save_attachments),
3993 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3994 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3995 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3996 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3998 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3999 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_new_msg),
4000 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
4001 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
4002 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
4003 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
4005 modest_window_add_to_menu (MODEST_WINDOW (self), _("mcen_ti_message_properties"), NULL,
4006 MODEST_WINDOW_MENU_CALLBACK (modest_ui_actions_on_details),
4007 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
4011 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
4013 ModestMsgViewWindowPrivate *priv;
4014 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4015 GSList *recipients = NULL;
4018 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
4022 header = modest_msg_view_window_get_header (self);
4025 recipients = modest_tny_msg_header_get_all_recipients_list (header);
4026 g_object_unref (header);
4028 recipients = modest_tny_msg_get_all_recipients_list (msg);
4029 g_object_unref (msg);
4033 /* Offer the user to add recipients to the address book */
4034 modest_address_book_add_address_list_with_selector (recipients, (GtkWindow *) self);
4035 g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);
4040 _modest_msg_view_window_map_event (GtkWidget *widget,
4044 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
4046 update_progress_hint (self);
4052 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
4054 ModestMsgViewWindowPrivate *priv;
4055 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4057 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
4061 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
4063 ModestMsgViewWindowPrivate *priv;
4064 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4066 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
4068 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
4072 modest_msg_view_window_reload (ModestMsgViewWindow *self)
4074 ModestMsgViewWindowPrivate *priv;
4075 const gchar *msg_uid;
4076 TnyHeader *header = NULL;
4077 TnyFolder *folder = NULL;
4079 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
4081 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4083 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
4087 folder = tny_header_get_folder (header);
4088 g_object_unref (header);
4093 msg_uid = modest_msg_view_window_get_message_uid (self);
4095 GtkTreeRowReference *row_reference;
4097 if (priv->row_reference && gtk_tree_row_reference_valid (priv->row_reference)) {
4098 row_reference = priv->row_reference;
4100 row_reference = NULL;
4102 if (!message_reader (self, priv, NULL, msg_uid, folder, row_reference))
4103 g_warning ("Shouldn't happen, trying to reload a message failed");
4106 g_object_unref (folder);
4110 update_branding (ModestMsgViewWindow *self)
4112 const gchar *account;
4113 const gchar *mailbox;
4114 ModestAccountMgr *mgr;
4115 ModestProtocol *protocol = NULL;
4116 gchar *service_name = NULL;
4117 const GdkPixbuf *service_icon = NULL;
4118 ModestMsgViewWindowPrivate *priv;
4120 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
4122 account = modest_window_get_active_account (MODEST_WINDOW (self));
4123 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
4125 mgr = modest_runtime_get_account_mgr ();
4127 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
4128 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4129 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
4131 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
4132 account, mailbox, MODEST_ICON_SIZE_SMALL);
4136 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
4137 g_free (service_name);
4141 sync_flags (ModestMsgViewWindow *self)
4143 TnyHeader *header = NULL;
4145 header = modest_msg_view_window_get_header (self);
4147 TnyMsg *msg = modest_msg_view_window_get_message (self);
4149 header = tny_msg_get_header (msg);
4150 g_object_unref (msg);
4155 TnyFolder *folder = tny_header_get_folder (header);
4158 ModestMailOperation *mail_op;
4160 /* Sync folder, we need this to save the seen flag */
4161 mail_op = modest_mail_operation_new (NULL);
4162 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
4164 modest_mail_operation_sync_folder (mail_op, folder, FALSE, NULL, NULL);
4165 g_object_unref (mail_op);
4166 g_object_unref (folder);
4168 g_object_unref (header);
4172 #ifdef MODEST_TOOLKIT_HILDON2
4174 on_realize (GtkWidget *widget,
4177 GdkDisplay *display;
4179 unsigned long val = 1;
4181 display = gdk_drawable_get_display (widget->window);
4182 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_ZOOM_KEY_ATOM");
4183 XChangeProperty (GDK_DISPLAY_XDISPLAY (display),
4184 GDK_WINDOW_XID (widget->window), atom,
4185 XA_INTEGER, 32, PropModeReplace,
4186 (unsigned char *) &val, 1);
4193 on_handle_calendar (ModestMsgView *msgview, TnyMimePart *calendar_part, GtkContainer *container, ModestMsgViewWindow *self)
4195 const gchar *account_name;
4196 ModestProtocolType proto_type;
4197 ModestProtocol *protocol;
4198 gboolean retval = FALSE;
4200 account_name = modest_window_get_active_account (MODEST_WINDOW (self));
4203 proto_type = modest_account_mgr_get_store_protocol (modest_runtime_get_account_mgr (),
4206 modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
4209 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
4210 retval = modest_account_protocol_handle_calendar (MODEST_ACCOUNT_PROTOCOL (protocol), MODEST_WINDOW (self),
4211 calendar_part, container);