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 "modest-marshal.h"
37 #include "modest-platform.h"
38 #include <modest-utils.h>
39 #include <modest-maemo-utils.h>
40 #include <modest-tny-msg.h>
41 #include <modest-msg-view-window.h>
42 #include <modest-main-window-ui.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-runtime.h>
46 #include <modest-window-priv.h>
47 #include <modest-tny-folder.h>
48 #include <modest-text-utils.h>
49 #include <modest-account-mgr-helpers.h>
50 #include "modest-progress-bar.h"
51 #include "modest-defs.h"
52 #include "modest-hildon-includes.h"
53 #include "modest-ui-dimming-manager.h"
54 #include <gdk/gdkkeysyms.h>
55 #include <modest-tny-account.h>
56 #include <modest-mime-part-view.h>
57 #include <modest-isearch-view.h>
58 #include <modest-tny-mime-part.h>
61 #include <glib/gstdio.h>
62 #include <modest-debug.h>
64 #define DEFAULT_FOLDER "MyDocs/.documents"
66 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
67 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
68 static void modest_header_view_observer_init(
69 ModestHeaderViewObserverIface *iface_class);
70 static void modest_msg_view_window_finalize (GObject *obj);
71 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
73 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
74 ModestMsgViewWindow *obj);
75 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
76 ModestMsgViewWindow *obj);
78 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
79 static void modest_msg_view_window_set_zoom (ModestWindow *window,
81 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
82 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
83 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
84 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
87 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
88 GdkEventWindowState *event,
90 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
92 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
93 gboolean show_toolbar);
95 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
97 ModestMsgViewWindow *window);
99 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
102 ModestMsgViewWindow *window);
104 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
106 ModestMsgViewWindow *window);
108 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
117 ModestMsgViewWindow *window);
119 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
121 const gchar *tny_folder_id);
123 static void cancel_progressbar (GtkToolButton *toolbutton,
124 ModestMsgViewWindow *self);
126 static void on_queue_changed (ModestMailOperationQueue *queue,
127 ModestMailOperation *mail_op,
128 ModestMailOperationQueueNotification type,
129 ModestMsgViewWindow *self);
131 static void on_account_removed (TnyAccountStore *account_store,
135 static void on_move_focus (GtkWidget *widget,
136 GtkDirectionType direction,
139 static void view_msg_cb (ModestMailOperation *mail_op,
146 static void set_toolbar_mode (ModestMsgViewWindow *self,
147 ModestToolBarModes mode);
149 static void update_window_title (ModestMsgViewWindow *window);
151 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
152 static void init_window (ModestMsgViewWindow *obj);
154 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
156 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
158 static gboolean on_fetch_image (ModestMsgView *msgview,
161 ModestMsgViewWindow *window);
163 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
164 GtkScrollType scroll_type,
168 /* list my signals */
175 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
176 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
177 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
180 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
181 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
182 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
183 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
184 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
185 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
186 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
189 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
190 struct _ModestMsgViewWindowPrivate {
193 GtkWidget *main_scroll;
194 GtkWidget *find_toolbar;
197 /* Progress observers */
198 GtkWidget *progress_bar;
199 GSList *progress_widgets;
202 GtkWidget *progress_toolitem;
203 GtkWidget *cancel_toolitem;
204 GtkWidget *prev_toolitem;
205 GtkWidget *next_toolitem;
206 ModestToolBarModes current_toolbar_mode;
208 /* Optimized view enabled */
209 gboolean optimized_view;
211 /* Whether this was created via the *_new_for_search_result() function. */
212 gboolean is_search_result;
214 /* Whether the message is in outbox */
217 /* A reference to the @model of the header view
218 * to allow selecting previous/next messages,
219 * if the message is currently selected in the header view.
221 const gchar *header_folder_id;
222 GtkTreeModel *header_model;
223 GtkTreeRowReference *row_reference;
224 GtkTreeRowReference *next_row_reference;
226 gulong clipboard_change_handler;
227 gulong queue_change_handler;
228 gulong account_removed_handler;
229 gulong row_changed_handler;
230 gulong row_deleted_handler;
231 gulong row_inserted_handler;
232 gulong rows_reordered_handler;
235 GtkWidget *remove_attachment_banner;
237 guint progress_bar_timeout;
240 TnyMimePart *other_body;
245 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
246 MODEST_TYPE_MSG_VIEW_WINDOW, \
247 ModestMsgViewWindowPrivate))
249 static GtkWindowClass *parent_class = NULL;
251 /* uncomment the following if you have defined any signals */
252 static guint signals[LAST_SIGNAL] = {0};
255 modest_msg_view_window_get_type (void)
257 static GType my_type = 0;
259 static const GTypeInfo my_info = {
260 sizeof(ModestMsgViewWindowClass),
261 NULL, /* base init */
262 NULL, /* base finalize */
263 (GClassInitFunc) modest_msg_view_window_class_init,
264 NULL, /* class finalize */
265 NULL, /* class data */
266 sizeof(ModestMsgViewWindow),
268 (GInstanceInitFunc) modest_msg_view_window_init,
271 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
272 "ModestMsgViewWindow",
275 static const GInterfaceInfo modest_header_view_observer_info =
277 (GInterfaceInitFunc) modest_header_view_observer_init,
278 NULL, /* interface_finalize */
279 NULL /* interface_data */
282 g_type_add_interface_static (my_type,
283 MODEST_TYPE_HEADER_VIEW_OBSERVER,
284 &modest_header_view_observer_info);
290 save_state (ModestWindow *self)
292 modest_widget_memory_save (modest_runtime_get_conf (),
294 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
299 restore_settings (ModestMsgViewWindow *self)
302 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
305 conf = modest_runtime_get_conf ();
306 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
307 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
308 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
309 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
310 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
311 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
312 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
313 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
314 modest_widget_memory_restore (conf,
316 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
319 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
320 GtkScrollType scroll_type,
324 ModestMsgViewWindowPrivate *priv;
325 gboolean return_value;
327 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
328 g_signal_emit_by_name (priv->main_scroll, "scroll-child", scroll_type, horizontal, &return_value);
333 add_scroll_binding (GtkBindingSet *binding_set,
335 GtkScrollType scroll)
337 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
339 gtk_binding_entry_add_signal (binding_set, keyval, 0,
341 GTK_TYPE_SCROLL_TYPE, scroll,
342 G_TYPE_BOOLEAN, FALSE);
343 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
345 GTK_TYPE_SCROLL_TYPE, scroll,
346 G_TYPE_BOOLEAN, FALSE);
350 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
352 GObjectClass *gobject_class;
353 ModestWindowClass *modest_window_class;
354 GtkBindingSet *binding_set;
356 gobject_class = (GObjectClass*) klass;
357 modest_window_class = (ModestWindowClass *) klass;
359 parent_class = g_type_class_peek_parent (klass);
360 gobject_class->finalize = modest_msg_view_window_finalize;
362 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
363 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
364 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
365 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
366 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
367 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
369 modest_window_class->save_state_func = save_state;
371 klass->scroll_child = modest_msg_view_window_scroll_child;
373 signals[MSG_CHANGED_SIGNAL] =
374 g_signal_new ("msg-changed",
375 G_TYPE_FROM_CLASS (gobject_class),
377 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
379 modest_marshal_VOID__POINTER_POINTER,
380 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
382 signals[SCROLL_CHILD_SIGNAL] =
383 g_signal_new ("scroll-child",
384 G_TYPE_FROM_CLASS (gobject_class),
385 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
386 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
388 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
389 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
391 binding_set = gtk_binding_set_by_class (klass);
392 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
393 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
394 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
395 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
396 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
397 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
399 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
403 static void modest_header_view_observer_init(
404 ModestHeaderViewObserverIface *iface_class)
406 iface_class->update_func = modest_msg_view_window_update_model_replaced;
410 modest_msg_view_window_init (ModestMsgViewWindow *obj)
412 ModestMsgViewWindowPrivate *priv;
413 ModestWindowPrivate *parent_priv = NULL;
414 GtkActionGroup *action_group = NULL;
415 GError *error = NULL;
416 GdkPixbuf *window_icon;
418 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
419 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
420 parent_priv->ui_manager = gtk_ui_manager_new();
422 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
423 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
425 /* Add common actions */
426 gtk_action_group_add_actions (action_group,
427 modest_action_entries,
428 G_N_ELEMENTS (modest_action_entries),
430 gtk_action_group_add_toggle_actions (action_group,
431 modest_toggle_action_entries,
432 G_N_ELEMENTS (modest_toggle_action_entries),
434 gtk_action_group_add_toggle_actions (action_group,
435 msg_view_toggle_action_entries,
436 G_N_ELEMENTS (msg_view_toggle_action_entries),
438 gtk_action_group_add_radio_actions (action_group,
439 msg_view_zoom_action_entries,
440 G_N_ELEMENTS (msg_view_zoom_action_entries),
442 G_CALLBACK (modest_ui_actions_on_change_zoom),
445 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
446 g_object_unref (action_group);
448 /* Load the UI definition */
449 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
452 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
453 g_error_free (error);
458 /* Add accelerators */
459 gtk_window_add_accel_group (GTK_WINDOW (obj),
460 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
462 priv->is_search_result = FALSE;
463 priv->is_outbox = FALSE;
465 priv->msg_view = NULL;
466 priv->header_model = NULL;
467 priv->header_folder_id = NULL;
468 priv->clipboard_change_handler = 0;
469 priv->queue_change_handler = 0;
470 priv->account_removed_handler = 0;
471 priv->row_changed_handler = 0;
472 priv->row_deleted_handler = 0;
473 priv->row_inserted_handler = 0;
474 priv->rows_reordered_handler = 0;
475 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
477 priv->optimized_view = FALSE;
478 priv->progress_bar_timeout = 0;
479 priv->purge_timeout = 0;
480 priv->remove_attachment_banner = NULL;
481 priv->msg_uid = NULL;
482 priv->other_body = NULL;
484 priv->sighandlers = NULL;
487 init_window (MODEST_MSG_VIEW_WINDOW(obj));
489 /* Set window icon */
490 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
492 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
493 g_object_unref (window_icon);
496 hildon_program_add_window (hildon_program_get_instance(),
499 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
500 GTK_WINDOW(obj),"applications_email_viewer");
505 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
507 ModestMsgViewWindowPrivate *priv = NULL;
509 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
511 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
513 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
515 if (priv->progress_bar_timeout > 0) {
516 g_source_remove (priv->progress_bar_timeout);
517 priv->progress_bar_timeout = 0;
524 set_toolbar_mode (ModestMsgViewWindow *self,
525 ModestToolBarModes mode)
527 ModestWindowPrivate *parent_priv;
528 ModestMsgViewWindowPrivate *priv;
529 /* GtkWidget *widget = NULL; */
531 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
533 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
534 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
536 /* Sets current toolbar mode */
537 priv->current_toolbar_mode = mode;
539 /* Update toolbar dimming state */
540 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
543 case TOOLBAR_MODE_NORMAL:
544 if (priv->progress_toolitem) {
545 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
546 gtk_widget_hide (priv->progress_toolitem);
549 if (priv->progress_bar)
550 gtk_widget_hide (priv->progress_bar);
552 if (priv->cancel_toolitem)
553 gtk_widget_hide (priv->cancel_toolitem);
555 if (priv->prev_toolitem)
556 gtk_widget_show (priv->prev_toolitem);
558 if (priv->next_toolitem)
559 gtk_widget_show (priv->next_toolitem);
561 /* Hide toolbar if optimized view is enabled */
562 if (priv->optimized_view) {
563 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
564 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
568 case TOOLBAR_MODE_TRANSFER:
569 if (priv->prev_toolitem)
570 gtk_widget_hide (priv->prev_toolitem);
572 if (priv->next_toolitem)
573 gtk_widget_hide (priv->next_toolitem);
575 if (priv->progress_bar)
576 gtk_widget_show (priv->progress_bar);
578 if (priv->progress_toolitem) {
579 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
580 gtk_widget_show (priv->progress_toolitem);
583 if (priv->cancel_toolitem)
584 gtk_widget_show (priv->cancel_toolitem);
586 /* Show toolbar if it's hiden (optimized view ) */
587 if (priv->optimized_view) {
588 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
589 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
594 g_return_if_reached ();
601 init_window (ModestMsgViewWindow *obj)
603 GtkWidget *main_vbox;
604 ModestMsgViewWindowPrivate *priv;
606 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
608 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
609 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
610 main_vbox = gtk_vbox_new (FALSE, 6);
612 #ifdef MODEST_USE_MOZEMBED
613 priv->main_scroll = priv->msg_view;
614 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
616 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
617 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
619 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
620 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
621 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
623 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
624 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
626 priv->find_toolbar = hildon_find_toolbar_new (NULL);
627 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
628 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
630 gtk_widget_show_all (GTK_WIDGET(main_vbox));
634 modest_msg_view_window_disconnect_signals (ModestWindow *self)
636 ModestMsgViewWindowPrivate *priv;
637 ModestHeaderView *header_view = NULL;
638 ModestWindow *main_window = NULL;
640 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
642 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
643 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
644 priv->clipboard_change_handler))
645 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
646 priv->clipboard_change_handler);
648 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
649 priv->queue_change_handler))
650 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
651 priv->queue_change_handler);
653 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
654 priv->account_removed_handler))
655 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
656 priv->account_removed_handler);
658 if (priv->header_model) {
659 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
660 priv->row_changed_handler))
661 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
662 priv->row_changed_handler);
664 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
665 priv->row_deleted_handler))
666 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
667 priv->row_deleted_handler);
669 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
670 priv->row_inserted_handler))
671 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
672 priv->row_inserted_handler);
674 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
675 priv->rows_reordered_handler))
676 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
677 priv->rows_reordered_handler);
680 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
681 priv->sighandlers = NULL;
683 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
684 FALSE); /* don't create */
688 header_view = MODEST_HEADER_VIEW(
689 modest_main_window_get_child_widget(
690 MODEST_MAIN_WINDOW(main_window),
691 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
692 if (header_view == NULL)
695 modest_header_view_remove_observer(header_view,
696 MODEST_HEADER_VIEW_OBSERVER(self));
700 modest_msg_view_window_finalize (GObject *obj)
702 ModestMsgViewWindowPrivate *priv;
704 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
706 /* Sanity check: shouldn't be needed, the window mgr should
707 call this function before */
708 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
710 if (priv->other_body != NULL) {
711 g_object_unref (priv->other_body);
712 priv->other_body = NULL;
715 if (priv->header_model != NULL) {
716 g_object_unref (priv->header_model);
717 priv->header_model = NULL;
720 if (priv->progress_bar_timeout > 0) {
721 g_source_remove (priv->progress_bar_timeout);
722 priv->progress_bar_timeout = 0;
725 if (priv->remove_attachment_banner) {
726 gtk_widget_destroy (priv->remove_attachment_banner);
727 g_object_unref (priv->remove_attachment_banner);
728 priv->remove_attachment_banner = NULL;
731 if (priv->purge_timeout > 0) {
732 g_source_remove (priv->purge_timeout);
733 priv->purge_timeout = 0;
736 if (priv->row_reference) {
737 gtk_tree_row_reference_free (priv->row_reference);
738 priv->row_reference = NULL;
741 if (priv->next_row_reference) {
742 gtk_tree_row_reference_free (priv->next_row_reference);
743 priv->next_row_reference = NULL;
747 g_free (priv->msg_uid);
748 priv->msg_uid = NULL;
751 G_OBJECT_CLASS(parent_class)->finalize (obj);
755 select_next_valid_row (GtkTreeModel *model,
756 GtkTreeRowReference **row_reference,
760 GtkTreeIter tmp_iter;
762 GtkTreePath *next = NULL;
763 gboolean retval = FALSE, finished;
765 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
767 path = gtk_tree_row_reference_get_path (*row_reference);
768 gtk_tree_model_get_iter (model, &tmp_iter, path);
769 gtk_tree_row_reference_free (*row_reference);
770 *row_reference = NULL;
774 TnyHeader *header = NULL;
776 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
777 gtk_tree_model_get (model, &tmp_iter,
778 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
782 if (msg_is_visible (header, is_outbox)) {
783 next = gtk_tree_model_get_path (model, &tmp_iter);
784 *row_reference = gtk_tree_row_reference_new (model, next);
785 gtk_tree_path_free (next);
789 g_object_unref (header);
792 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
793 next = gtk_tree_model_get_path (model, &tmp_iter);
795 /* Ensure that we are not selecting the same */
796 if (gtk_tree_path_compare (path, next) != 0) {
797 gtk_tree_model_get (model, &tmp_iter,
798 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
801 if (msg_is_visible (header, is_outbox)) {
802 *row_reference = gtk_tree_row_reference_new (model, next);
806 g_object_unref (header);
810 /* If we ended up in the same message
811 then there is no valid next
815 gtk_tree_path_free (next);
817 /* If there are no more messages and we don't
818 want to start again in the first one then
819 there is no valid next message */
825 gtk_tree_path_free (path);
830 /* TODO: This should be in _init(), with the parameters as properties. */
832 modest_msg_view_window_construct (ModestMsgViewWindow *self,
833 const gchar *modest_account_name,
834 const gchar *msg_uid)
837 ModestMsgViewWindowPrivate *priv = NULL;
838 ModestWindowPrivate *parent_priv = NULL;
839 ModestDimmingRulesGroup *menu_rules_group = NULL;
840 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
841 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
843 obj = G_OBJECT (self);
844 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
845 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
847 priv->msg_uid = g_strdup (msg_uid);
850 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
851 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
852 gtk_widget_show (parent_priv->menubar);
853 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
855 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
856 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
857 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
859 /* Add common dimming rules */
860 modest_dimming_rules_group_add_rules (menu_rules_group,
861 modest_msg_view_menu_dimming_entries,
862 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
863 MODEST_WINDOW (self));
864 modest_dimming_rules_group_add_rules (toolbar_rules_group,
865 modest_msg_view_toolbar_dimming_entries,
866 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
867 MODEST_WINDOW (self));
868 modest_dimming_rules_group_add_rules (clipboard_rules_group,
869 modest_msg_view_clipboard_dimming_entries,
870 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
871 MODEST_WINDOW (self));
873 /* Insert dimming rules group for this window */
874 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
875 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
876 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
877 g_object_unref (menu_rules_group);
878 g_object_unref (toolbar_rules_group);
879 g_object_unref (clipboard_rules_group);
881 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
883 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
885 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);
886 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
887 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
888 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
889 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
890 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
891 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
892 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
893 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
894 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
895 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
896 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
897 G_CALLBACK (on_fetch_image), obj);
899 g_signal_connect (G_OBJECT (obj), "key-release-event",
900 G_CALLBACK (modest_msg_view_window_key_event),
903 g_signal_connect (G_OBJECT (obj), "key-press-event",
904 G_CALLBACK (modest_msg_view_window_key_event),
907 g_signal_connect (G_OBJECT (obj), "window-state-event",
908 G_CALLBACK (modest_msg_view_window_window_state_event),
911 g_signal_connect (G_OBJECT (obj), "move-focus",
912 G_CALLBACK (on_move_focus), obj);
914 /* Mail Operation Queue */
915 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
917 G_CALLBACK (on_queue_changed),
920 /* Account manager */
921 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
923 G_CALLBACK(on_account_removed),
926 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
928 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
929 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
930 priv->last_search = NULL;
932 /* Init the clipboard actions dim status */
933 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
935 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
940 /* FIXME: parameter checks */
942 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
943 const gchar *modest_account_name,
944 const gchar *mailbox, /*ignored */
945 const gchar *msg_uid,
947 GtkTreeRowReference *row_reference)
949 ModestMsgViewWindow *window = NULL;
950 ModestMsgViewWindowPrivate *priv = NULL;
951 TnyFolder *header_folder = NULL;
952 ModestHeaderView *header_view = NULL;
953 ModestWindow *main_window = NULL;
954 ModestWindowMgr *mgr = NULL;
957 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
960 mgr = modest_runtime_get_window_mgr ();
961 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
962 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
964 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
966 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
968 /* Remember the message list's TreeModel so we can detect changes
969 * and change the list selection when necessary: */
971 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
973 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
974 MODEST_MAIN_WINDOW(main_window),
975 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
978 if (header_view != NULL){
979 header_folder = modest_header_view_get_folder(header_view);
980 /* This could happen if the header folder was
981 unseleted before opening this msg window (for
982 example if the user selects an account in the
983 folder view of the main window */
985 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) == TNY_FOLDER_TYPE_OUTBOX);
986 priv->header_folder_id = tny_folder_get_id(header_folder);
987 g_assert(priv->header_folder_id != NULL);
988 g_object_unref(header_folder);
992 /* Setup row references and connect signals */
993 priv->header_model = g_object_ref (model);
996 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
997 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
998 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1000 priv->row_reference = NULL;
1001 priv->next_row_reference = NULL;
1004 /* Connect signals */
1005 priv->row_changed_handler =
1006 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
1007 G_CALLBACK(modest_msg_view_window_on_row_changed),
1009 priv->row_deleted_handler =
1010 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
1011 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1013 priv->row_inserted_handler =
1014 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
1015 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1017 priv->rows_reordered_handler =
1018 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
1019 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1022 if (header_view != NULL){
1023 modest_header_view_add_observer(header_view,
1024 MODEST_HEADER_VIEW_OBSERVER(window));
1027 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1028 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
1029 gtk_widget_show_all (GTK_WIDGET (window));
1030 modest_msg_view_window_update_priority (window);
1032 /* Check dimming rules */
1033 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1034 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1035 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1037 return MODEST_WINDOW(window);
1041 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1042 const gchar *modest_account_name,
1043 const gchar *mailbox, /*ignored*/
1044 const gchar *msg_uid)
1046 ModestMsgViewWindow *window = NULL;
1047 ModestMsgViewWindowPrivate *priv = NULL;
1048 ModestWindowMgr *mgr = NULL;
1050 mgr = modest_runtime_get_window_mgr ();
1051 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1052 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1053 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
1055 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1057 /* Remember that this is a search result,
1058 * so we can disable some UI appropriately: */
1059 priv->is_search_result = TRUE;
1061 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1063 update_window_title (window);
1064 gtk_widget_show_all (GTK_WIDGET (window));
1065 modest_msg_view_window_update_priority (window);
1067 /* Check dimming rules */
1068 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1069 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1070 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1072 return MODEST_WINDOW(window);
1076 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1078 ModestMsgViewWindowPrivate *priv = NULL;
1080 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1081 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1083 return (priv->other_body != NULL);
1087 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1088 TnyMimePart *other_body,
1089 const gchar *modest_account_name,
1090 const gchar *mailbox, /* ignored */
1091 const gchar *msg_uid)
1093 GObject *obj = NULL;
1094 ModestMsgViewWindowPrivate *priv;
1095 ModestWindowMgr *mgr = NULL;
1097 g_return_val_if_fail (msg, NULL);
1098 mgr = modest_runtime_get_window_mgr ();
1099 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1100 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1101 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1102 modest_account_name, msg_uid);
1105 priv->other_body = g_object_ref (other_body);
1106 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1108 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1110 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1112 gtk_widget_show_all (GTK_WIDGET (obj));
1114 /* Check dimming rules */
1115 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1116 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1117 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1119 return MODEST_WINDOW(obj);
1123 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1124 const gchar *modest_account_name,
1125 const gchar *mailbox, /* ignored */
1126 const gchar *msg_uid)
1128 return modest_msg_view_window_new_with_other_body (msg, NULL, modest_account_name, mailbox, msg_uid);
1133 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1136 ModestMsgViewWindow *window)
1138 check_dimming_rules_after_change (window);
1142 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1144 ModestMsgViewWindow *window)
1146 check_dimming_rules_after_change (window);
1148 /* The window could have dissapeared */
1151 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1153 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1154 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1158 /* On insertions we check if the folder still has the message we are
1159 * showing or do not. If do not, we do nothing. Which means we are still
1160 * not attached to any header folder and thus next/prev buttons are
1161 * still dimmed. Once the message that is shown by msg-view is found, the
1162 * new model of header-view will be attached and the references will be set.
1163 * On each further insertions dimming rules will be checked. However
1164 * this requires extra CPU time at least works.
1165 * (An message might be deleted from TnyFolder and thus will not be
1166 * inserted into the model again for example if it is removed by the
1167 * imap server and the header view is refreshed.)
1170 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1171 GtkTreePath *tree_path,
1172 GtkTreeIter *tree_iter,
1173 ModestMsgViewWindow *window)
1175 ModestMsgViewWindowPrivate *priv = NULL;
1176 TnyHeader *header = NULL;
1178 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1179 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1181 g_assert (model == priv->header_model);
1183 /* Check if the newly inserted message is the same we are actually
1184 * showing. IF not, we should remain detached from the header model
1185 * and thus prev and next toolbar buttons should remain dimmed. */
1186 gtk_tree_model_get (model, tree_iter,
1187 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1190 if (TNY_IS_HEADER (header)) {
1193 uid = modest_tny_folder_get_header_unique_id (header);
1194 if (!g_str_equal(priv->msg_uid, uid)) {
1195 check_dimming_rules_after_change (window);
1197 g_object_unref (G_OBJECT(header));
1201 g_object_unref(G_OBJECT(header));
1204 if (priv->row_reference) {
1205 gtk_tree_row_reference_free (priv->row_reference);
1208 /* Setup row_reference for the actual msg. */
1209 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1210 if (priv->row_reference == NULL) {
1211 g_warning("No reference for msg header item.");
1215 /* Now set up next_row_reference. */
1216 if (priv->next_row_reference) {
1217 gtk_tree_row_reference_free (priv->next_row_reference);
1220 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1221 select_next_valid_row (priv->header_model,
1222 &(priv->next_row_reference), FALSE, priv->is_outbox);
1224 /* Connect the remaining callbacks to become able to detect
1225 * changes in header-view. */
1226 priv->row_changed_handler =
1227 g_signal_connect (priv->header_model, "row-changed",
1228 G_CALLBACK (modest_msg_view_window_on_row_changed),
1230 priv->row_deleted_handler =
1231 g_signal_connect (priv->header_model, "row-deleted",
1232 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1234 priv->rows_reordered_handler =
1235 g_signal_connect (priv->header_model, "rows-reordered",
1236 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1239 check_dimming_rules_after_change (window);
1243 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1247 ModestMsgViewWindow *window)
1249 ModestMsgViewWindowPrivate *priv = NULL;
1250 gboolean already_changed = FALSE;
1252 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1254 /* If the current row was reordered select the proper next
1255 valid row. The same if the next row reference changes */
1256 if (priv->row_reference &&
1257 gtk_tree_row_reference_valid (priv->row_reference)) {
1259 path = gtk_tree_row_reference_get_path (priv->row_reference);
1260 if (gtk_tree_path_compare (path, arg1) == 0) {
1261 if (priv->next_row_reference) {
1262 gtk_tree_row_reference_free (priv->next_row_reference);
1264 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1265 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1266 already_changed = TRUE;
1268 gtk_tree_path_free (path);
1270 if (!already_changed &&
1271 priv->next_row_reference &&
1272 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1274 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1275 if (gtk_tree_path_compare (path, arg1) == 0) {
1276 if (priv->next_row_reference) {
1277 gtk_tree_row_reference_free (priv->next_row_reference);
1279 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1280 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1282 gtk_tree_path_free (path);
1284 check_dimming_rules_after_change (window);
1287 /* The modest_msg_view_window_update_model_replaced implements update
1288 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1289 * actually belongs to the header-view is the same as the TnyFolder of
1290 * the message of msg-view or not. If they are different, there is
1291 * nothing to do. If they are the same, then the model has replaced and
1292 * the reference in msg-view shall be replaced from the old model to
1293 * the new model. In this case the view will be detached from it's
1294 * header folder. From this point the next/prev buttons are dimmed.
1297 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1298 GtkTreeModel *model,
1299 const gchar *tny_folder_id)
1301 ModestMsgViewWindowPrivate *priv = NULL;
1302 ModestMsgViewWindow *window = NULL;
1304 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1305 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1307 window = MODEST_MSG_VIEW_WINDOW(observer);
1308 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1310 /* If there is an other folder in the header-view then we do
1311 * not care about it's model (msg list). Else if the
1312 * header-view shows the folder the msg shown by us is in, we
1313 * shall replace our model reference and make some check. */
1314 if(model == NULL || tny_folder_id == NULL ||
1315 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1318 /* Model is changed(replaced), so we should forget the old
1319 * one. Because there might be other references and there
1320 * might be some change on the model even if we unreferenced
1321 * it, we need to disconnect our signals here. */
1322 if (priv->header_model) {
1323 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1324 priv->row_changed_handler))
1325 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1326 priv->row_changed_handler);
1327 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1328 priv->row_deleted_handler))
1329 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1330 priv->row_deleted_handler);
1331 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1332 priv->row_inserted_handler))
1333 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1334 priv->row_inserted_handler);
1335 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1336 priv->rows_reordered_handler))
1337 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1338 priv->rows_reordered_handler);
1341 if (priv->row_reference)
1342 gtk_tree_row_reference_free (priv->row_reference);
1343 if (priv->next_row_reference)
1344 gtk_tree_row_reference_free (priv->next_row_reference);
1345 g_object_unref(priv->header_model);
1348 priv->row_changed_handler = 0;
1349 priv->row_deleted_handler = 0;
1350 priv->row_inserted_handler = 0;
1351 priv->rows_reordered_handler = 0;
1352 priv->next_row_reference = NULL;
1353 priv->row_reference = NULL;
1354 priv->header_model = NULL;
1357 priv->header_model = g_object_ref (model);
1359 /* Also we must connect to the new model for row insertions.
1360 * Only for insertions now. We will need other ones only after
1361 * the msg is show by msg-view is added to the new model. */
1362 priv->row_inserted_handler =
1363 g_signal_connect (priv->header_model, "row-inserted",
1364 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1367 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1368 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1372 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1374 ModestMsgViewWindowPrivate *priv= NULL;
1376 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1377 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1379 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1383 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1385 ModestMsgViewWindowPrivate *priv= NULL;
1387 TnyHeader *header = NULL;
1388 GtkTreePath *path = NULL;
1391 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1392 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1394 /* If the message was not obtained from a treemodel,
1395 * for instance if it was opened directly by the search UI:
1397 if (priv->header_model == NULL ||
1398 priv->row_reference == NULL ||
1399 !gtk_tree_row_reference_valid (priv->row_reference)) {
1400 msg = modest_msg_view_window_get_message (self);
1402 header = tny_msg_get_header (msg);
1403 g_object_unref (msg);
1408 /* Get iter of the currently selected message in the header view: */
1409 path = gtk_tree_row_reference_get_path (priv->row_reference);
1410 g_return_val_if_fail (path != NULL, NULL);
1411 gtk_tree_model_get_iter (priv->header_model,
1415 /* Get current message header */
1416 gtk_tree_model_get (priv->header_model, &iter,
1417 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1420 gtk_tree_path_free (path);
1425 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1427 ModestMsgViewWindowPrivate *priv;
1429 g_return_val_if_fail (self, NULL);
1431 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1433 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1437 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1439 ModestMsgViewWindowPrivate *priv;
1441 g_return_val_if_fail (self, NULL);
1443 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1445 return (const gchar*) priv->msg_uid;
1449 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1452 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1453 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1454 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1458 is_active = gtk_toggle_action_get_active (toggle);
1461 gtk_widget_show (priv->find_toolbar);
1462 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1464 gtk_widget_hide (priv->find_toolbar);
1465 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1468 /* update the toggle buttons status */
1469 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1470 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1471 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1472 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1477 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1478 ModestMsgViewWindow *obj)
1480 GtkToggleAction *toggle;
1481 ModestWindowPrivate *parent_priv;
1482 ModestMsgViewWindowPrivate *priv;
1484 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1485 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1487 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1488 gtk_toggle_action_set_active (toggle, FALSE);
1489 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1493 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1494 ModestMsgViewWindow *obj)
1496 gchar *current_search;
1497 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1499 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1500 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1504 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1506 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1507 g_free (current_search);
1508 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
1512 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1514 g_free (priv->last_search);
1515 priv->last_search = g_strdup (current_search);
1516 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1519 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_no_matches"));
1520 g_free (priv->last_search);
1521 priv->last_search = NULL;
1523 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1524 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1527 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1528 hildon_banner_show_information (NULL, NULL, _HL("ckct_ib_find_search_complete"));
1529 g_free (priv->last_search);
1530 priv->last_search = NULL;
1532 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1533 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1537 g_free (current_search);
1542 modest_msg_view_window_set_zoom (ModestWindow *window,
1545 ModestMsgViewWindowPrivate *priv;
1546 ModestWindowPrivate *parent_priv;
1547 GtkAction *action = NULL;
1548 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1550 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1552 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1553 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1554 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1556 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1557 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1559 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1563 modest_msg_view_window_get_zoom (ModestWindow *window)
1565 ModestMsgViewWindowPrivate *priv;
1567 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1569 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1570 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1574 modest_msg_view_window_zoom_plus (ModestWindow *window)
1576 ModestWindowPrivate *parent_priv;
1577 GtkRadioAction *zoom_radio_action;
1578 GSList *group, *node;
1580 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1581 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1582 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1584 group = gtk_radio_action_get_group (zoom_radio_action);
1586 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1587 hildon_banner_show_information (NULL, NULL, _CS("ckct_ib_max_zoom_level_reached"));
1591 for (node = group; node != NULL; node = g_slist_next (node)) {
1592 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1593 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1601 modest_msg_view_window_zoom_minus (ModestWindow *window)
1603 ModestWindowPrivate *parent_priv;
1604 GtkRadioAction *zoom_radio_action;
1605 GSList *group, *node;
1607 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1608 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1609 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1611 group = gtk_radio_action_get_group (zoom_radio_action);
1613 for (node = group; node != NULL; node = g_slist_next (node)) {
1614 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1615 if (node->next != NULL) {
1616 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1619 hildon_banner_show_information (NULL, NULL,
1620 _CS("ckct_ib_min_zoom_level_reached"));
1630 modest_msg_view_window_key_event (GtkWidget *window,
1636 focus = gtk_window_get_focus (GTK_WINDOW (window));
1638 /* for the find toolbar case */
1639 if (focus && GTK_IS_ENTRY (focus)) {
1640 if (event->keyval == GDK_BackSpace) {
1642 copy = gdk_event_copy ((GdkEvent *) event);
1643 gtk_widget_event (focus, copy);
1644 gdk_event_free (copy);
1649 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1650 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1651 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1652 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1653 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1654 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1655 /* ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); */
1656 /* gboolean return_value; */
1658 if (event->type == GDK_KEY_PRESS) {
1659 GtkScrollType scroll_type;
1661 switch (event->keyval) {
1664 scroll_type = GTK_SCROLL_STEP_UP; break;
1667 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1669 case GDK_KP_Page_Up:
1670 scroll_type = GTK_SCROLL_PAGE_UP; break;
1672 case GDK_KP_Page_Down:
1673 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1676 scroll_type = GTK_SCROLL_START; break;
1679 scroll_type = GTK_SCROLL_END; break;
1680 default: scroll_type = GTK_SCROLL_NONE;
1683 /* g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", */
1684 /* scroll_type, FALSE, &return_value); */
1695 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1698 ModestMsgViewWindowPrivate *priv;
1699 GtkTreeIter tmp_iter;
1700 gboolean is_last_selected;
1702 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1703 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1705 /*if no model (so no rows at all), then virtually we are the last*/
1706 if (!priv->header_model || !priv->row_reference)
1709 if (!gtk_tree_row_reference_valid (priv->row_reference))
1712 path = gtk_tree_row_reference_get_path (priv->row_reference);
1716 is_last_selected = TRUE;
1717 while (is_last_selected) {
1719 gtk_tree_path_next (path);
1720 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1722 gtk_tree_model_get (priv->header_model, &tmp_iter,
1723 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1726 if (msg_is_visible (header, priv->is_outbox))
1727 is_last_selected = FALSE;
1728 g_object_unref(G_OBJECT(header));
1731 gtk_tree_path_free (path);
1732 return is_last_selected;
1736 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1738 ModestMsgViewWindowPrivate *priv;
1740 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1741 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1743 return priv->header_model != NULL;
1747 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1749 ModestMsgViewWindowPrivate *priv;
1751 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1752 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1754 return priv->is_search_result;
1758 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1760 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1762 if (!check_outbox) {
1765 ModestTnySendQueueStatus status;
1766 status = modest_tny_all_send_queues_get_msg_status (header);
1767 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1768 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1773 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1776 ModestMsgViewWindowPrivate *priv;
1777 gboolean is_first_selected;
1778 GtkTreeIter tmp_iter;
1780 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1781 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1783 /*if no model (so no rows at all), then virtually we are the first*/
1784 if (!priv->header_model || !priv->row_reference)
1787 if (!gtk_tree_row_reference_valid (priv->row_reference))
1790 path = gtk_tree_row_reference_get_path (priv->row_reference);
1794 is_first_selected = TRUE;
1795 while (is_first_selected) {
1797 if(!gtk_tree_path_prev (path))
1799 /* Here the 'if' is needless for logic, but let make sure
1800 * iter is valid for gtk_tree_model_get. */
1801 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1803 gtk_tree_model_get (priv->header_model, &tmp_iter,
1804 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1807 if (msg_is_visible (header, priv->is_outbox))
1808 is_first_selected = FALSE;
1809 g_object_unref(G_OBJECT(header));
1812 gtk_tree_path_free (path);
1813 return is_first_selected;
1818 GtkTreeRowReference *row_reference;
1822 message_reader_performer (gboolean canceled,
1824 GtkWindow *parent_window,
1825 TnyAccount *account,
1828 ModestMailOperation *mail_op = NULL;
1829 MsgReaderInfo *info;
1831 info = (MsgReaderInfo *) user_data;
1832 if (canceled || err) {
1836 /* Register the header - it'll be unregistered in the callback */
1837 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1839 /* New mail operation */
1840 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1841 modest_ui_actions_disk_operations_error_handler,
1844 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1845 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1846 g_object_unref (mail_op);
1848 /* Update dimming rules */
1849 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1850 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1853 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1854 g_object_unref (info->header);
1855 g_slice_free (MsgReaderInfo, info);
1860 * Reads the message whose summary item is @header. It takes care of
1861 * several things, among others:
1863 * If the message was not previously downloaded then ask the user
1864 * before downloading. If there is no connection launch the connection
1865 * dialog. Update toolbar dimming rules.
1867 * Returns: TRUE if the mail operation was started, otherwise if the
1868 * user do not want to download the message, or if the user do not
1869 * want to connect, then the operation is not issued
1872 message_reader (ModestMsgViewWindow *window,
1873 ModestMsgViewWindowPrivate *priv,
1875 GtkTreeRowReference *row_reference)
1877 gboolean already_showing = FALSE;
1878 ModestWindow *msg_window = NULL;
1879 ModestWindowMgr *mgr;
1880 TnyAccount *account;
1882 MsgReaderInfo *info;
1884 g_return_val_if_fail (row_reference != NULL, FALSE);
1886 mgr = modest_runtime_get_window_mgr ();
1887 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1888 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1891 gtk_window_present (GTK_WINDOW (msg_window));
1892 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1896 /* Msg download completed */
1897 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1898 /* Ask the user if he wants to download the message if
1900 if (!tny_device_is_online (modest_runtime_get_device())) {
1901 GtkResponseType response;
1903 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1904 _("mcen_nc_get_msg"));
1905 if (response == GTK_RESPONSE_CANCEL)
1908 folder = tny_header_get_folder (header);
1909 info = g_slice_new (MsgReaderInfo);
1910 info->header = g_object_ref (header);
1911 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1913 /* Offer the connection dialog if necessary */
1914 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
1916 TNY_FOLDER_STORE (folder),
1917 message_reader_performer,
1919 g_object_unref (folder);
1924 folder = tny_header_get_folder (header);
1925 account = tny_folder_get_account (folder);
1926 info = g_slice_new (MsgReaderInfo);
1927 info->header = g_object_ref (header);
1928 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1930 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
1931 g_object_unref (account);
1932 g_object_unref (folder);
1938 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1940 ModestMsgViewWindowPrivate *priv;
1941 GtkTreePath *path= NULL;
1942 GtkTreeIter tmp_iter;
1944 gboolean retval = TRUE;
1945 GtkTreeRowReference *row_reference = NULL;
1947 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1948 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1950 if (!priv->row_reference)
1953 /* Update the next row reference if it's not valid. This could
1954 happen if for example the header which it was pointing to,
1955 was deleted. The best place to do it is in the row-deleted
1956 handler but the tinymail model do not work like the glib
1957 tree models and reports the deletion when the row is still
1959 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1960 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1961 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1962 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1965 if (priv->next_row_reference)
1966 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1970 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1972 gtk_tree_model_get_iter (priv->header_model,
1975 gtk_tree_path_free (path);
1977 gtk_tree_model_get (priv->header_model, &tmp_iter,
1978 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1981 /* Read the message & show it */
1982 if (!message_reader (window, priv, header, row_reference)) {
1985 gtk_tree_row_reference_free (row_reference);
1988 g_object_unref (header);
1994 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1996 ModestMsgViewWindowPrivate *priv = NULL;
1998 gboolean finished = FALSE;
1999 gboolean retval = FALSE;
2001 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2002 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2004 /* Return inmediatly if there is no header model */
2005 if (!priv->header_model || !priv->row_reference)
2008 path = gtk_tree_row_reference_get_path (priv->row_reference);
2009 while (!finished && gtk_tree_path_prev (path)) {
2013 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2014 gtk_tree_model_get (priv->header_model, &iter,
2015 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2019 if (msg_is_visible (header, priv->is_outbox)) {
2020 GtkTreeRowReference *row_reference;
2021 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2022 /* Read the message & show it */
2023 retval = message_reader (window, priv, header, row_reference);
2024 gtk_tree_row_reference_free (row_reference);
2028 g_object_unref (header);
2032 gtk_tree_path_free (path);
2037 view_msg_cb (ModestMailOperation *mail_op,
2044 ModestMsgViewWindow *self = NULL;
2045 ModestMsgViewWindowPrivate *priv = NULL;
2046 GtkTreeRowReference *row_reference = NULL;
2048 /* Unregister the header (it was registered before creating the mail operation) */
2049 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2051 row_reference = (GtkTreeRowReference *) user_data;
2053 gtk_tree_row_reference_free (row_reference);
2057 /* If there was any error */
2058 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2059 gtk_tree_row_reference_free (row_reference);
2063 /* Get the window */
2064 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2065 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2066 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2068 /* Update the row reference */
2069 if (priv->row_reference != NULL) {
2070 gtk_tree_row_reference_free (priv->row_reference);
2071 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
2072 if (priv->next_row_reference != NULL) {
2073 gtk_tree_row_reference_free (priv->next_row_reference);
2075 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2076 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2079 /* Mark header as read */
2080 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2081 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2083 /* Set new message */
2084 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2085 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2086 modest_msg_view_window_update_priority (self);
2087 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2088 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2091 /* Set the new message uid of the window */
2092 if (priv->msg_uid) {
2093 g_free (priv->msg_uid);
2094 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2097 /* Notify the observers */
2098 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2099 0, priv->header_model, priv->row_reference);
2102 g_object_unref (self);
2103 gtk_tree_row_reference_free (row_reference);
2107 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2109 ModestMsgViewWindowPrivate *priv;
2111 TnyFolderType folder_type;
2113 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2115 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2117 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2121 folder = tny_msg_get_folder (msg);
2123 folder_type = modest_tny_folder_guess_folder_type (folder);
2124 g_object_unref (folder);
2126 g_object_unref (msg);
2134 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2136 ModestMsgViewWindowPrivate *priv;
2137 TnyHeader *header = NULL;
2138 TnyHeaderFlags flags = 0;
2140 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2142 if (priv->header_model && priv->row_reference) {
2144 GtkTreePath *path = NULL;
2146 path = gtk_tree_row_reference_get_path (priv->row_reference);
2147 g_return_if_fail (path != NULL);
2148 gtk_tree_model_get_iter (priv->header_model,
2150 gtk_tree_row_reference_get_path (priv->row_reference));
2152 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2154 gtk_tree_path_free (path);
2157 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2159 header = tny_msg_get_header (msg);
2160 g_object_unref (msg);
2165 flags = tny_header_get_flags (header);
2166 g_object_unref(G_OBJECT(header));
2169 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2174 toolbar_resize (ModestMsgViewWindow *self)
2176 ModestMsgViewWindowPrivate *priv = NULL;
2177 ModestWindowPrivate *parent_priv = NULL;
2179 gint static_button_size;
2180 ModestWindowMgr *mgr;
2182 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2183 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2184 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2186 mgr = modest_runtime_get_window_mgr ();
2187 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
2189 if (parent_priv->toolbar) {
2190 /* left size buttons */
2191 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2192 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2193 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2194 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2195 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
2196 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2197 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2198 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2199 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2200 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2201 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2202 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2203 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
2204 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2205 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2206 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2208 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2209 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2210 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
2211 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
2212 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2213 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2214 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2215 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2221 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2223 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2224 ModestWindowPrivate *parent_priv;
2225 ModestWindowMgr *mgr;
2226 gboolean is_fullscreen;
2227 GtkAction *fs_toggle_action;
2230 mgr = modest_runtime_get_window_mgr ();
2231 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2233 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2235 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2236 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2237 if (is_fullscreen != active) {
2238 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2240 toolbar_resize (MODEST_MSG_VIEW_WINDOW (widget));
2248 modest_msg_view_window_show_toolbar (ModestWindow *self,
2249 gboolean show_toolbar)
2251 ModestMsgViewWindowPrivate *priv = NULL;
2252 ModestWindowPrivate *parent_priv;
2253 GtkWidget *reply_button = NULL, *menu = NULL;
2254 GtkWidget *placeholder = NULL;
2256 const gchar *action_name;
2259 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2260 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2262 /* Set optimized view status */
2263 priv->optimized_view = !show_toolbar;
2265 if (!parent_priv->toolbar) {
2266 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2268 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2270 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
2271 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2272 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2273 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2274 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2276 /* Add ProgressBar (Transfer toolbar) */
2277 priv->progress_bar = modest_progress_bar_new ();
2278 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
2279 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
2280 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
2281 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
2282 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
2284 /* Connect cancel 'clicked' signal to abort progress mode */
2285 g_signal_connect(priv->cancel_toolitem, "clicked",
2286 G_CALLBACK(cancel_progressbar),
2289 /* Add it to the observers list */
2290 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
2293 hildon_window_add_toolbar (HILDON_WINDOW (self),
2294 GTK_TOOLBAR (parent_priv->toolbar));
2296 /* Set reply button tap and hold menu */
2297 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2298 "/ToolBar/ToolbarMessageReply");
2299 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2300 "/ToolbarReplyCSM");
2301 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2305 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2306 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2307 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2309 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2310 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2311 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2313 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2316 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2317 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2320 /* Update also the actions (to update the toggles in the
2321 menus), we have to do it manually because some other window
2322 of the same time could have changed it (remember that the
2323 toolbar fullscreen mode is shared by all the windows of the
2325 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2326 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2328 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2330 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2331 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2336 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2338 ModestMsgViewWindow *window)
2340 if (!GTK_WIDGET_VISIBLE (window))
2343 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2347 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2349 ModestMsgViewWindowPrivate *priv;
2351 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2352 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2354 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2358 cancel_progressbar (GtkToolButton *toolbutton,
2359 ModestMsgViewWindow *self)
2362 ModestMsgViewWindowPrivate *priv;
2364 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2366 /* Get operation observers and cancel its current operation */
2367 tmp = priv->progress_widgets;
2369 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2370 tmp=g_slist_next(tmp);
2374 observers_empty (ModestMsgViewWindow *self)
2377 ModestMsgViewWindowPrivate *priv;
2378 gboolean is_empty = TRUE;
2379 guint pending_ops = 0;
2381 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2382 tmp = priv->progress_widgets;
2384 /* Check all observers */
2385 while (tmp && is_empty) {
2386 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2387 is_empty = pending_ops == 0;
2389 tmp = g_slist_next(tmp);
2396 on_account_removed (TnyAccountStore *account_store,
2397 TnyAccount *account,
2400 /* Do nothing if it's a transport account, because we only
2401 show the messages of a store account */
2402 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2403 const gchar *parent_acc = NULL;
2404 const gchar *our_acc = NULL;
2406 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2407 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2409 /* Close this window if I'm showing a message of the removed account */
2410 if (strcmp (parent_acc, our_acc) == 0)
2411 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2416 on_mail_operation_started (ModestMailOperation *mail_op,
2419 ModestMsgViewWindow *self;
2420 ModestMailOperationTypeOperation op_type;
2422 ModestMsgViewWindowPrivate *priv;
2423 GObject *source = NULL;
2425 self = MODEST_MSG_VIEW_WINDOW (user_data);
2426 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2427 op_type = modest_mail_operation_get_type_operation (mail_op);
2428 tmp = priv->progress_widgets;
2429 source = modest_mail_operation_get_source(mail_op);
2430 if (G_OBJECT (self) == source) {
2431 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ) {
2432 set_toolbar_transfer_mode(self);
2434 modest_progress_object_add_operation (
2435 MODEST_PROGRESS_OBJECT (tmp->data),
2437 tmp = g_slist_next (tmp);
2441 g_object_unref (source);
2445 on_mail_operation_finished (ModestMailOperation *mail_op,
2448 ModestMsgViewWindow *self;
2449 ModestMailOperationTypeOperation op_type;
2451 ModestMsgViewWindowPrivate *priv;
2453 self = MODEST_MSG_VIEW_WINDOW (user_data);
2454 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2455 op_type = modest_mail_operation_get_type_operation (mail_op);
2456 tmp = priv->progress_widgets;
2458 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE ) {
2460 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2462 tmp = g_slist_next (tmp);
2465 /* If no more operations are being observed, NORMAL mode is enabled again */
2466 if (observers_empty (self)) {
2467 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2470 /* Update dimming rules. We have to do this right here
2471 and not in view_msg_cb because at that point the
2472 transfer mode is still enabled so the dimming rule
2473 won't let the user delete the message that has been
2474 readed for example */
2475 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2476 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2481 on_queue_changed (ModestMailOperationQueue *queue,
2482 ModestMailOperation *mail_op,
2483 ModestMailOperationQueueNotification type,
2484 ModestMsgViewWindow *self)
2486 ModestMsgViewWindowPrivate *priv;
2488 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2490 /* If this operations was created by another window, do nothing */
2491 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2494 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2495 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2497 "operation-started",
2498 G_CALLBACK (on_mail_operation_started),
2500 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2502 "operation-finished",
2503 G_CALLBACK (on_mail_operation_finished),
2505 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2506 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2508 "operation-started");
2509 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2511 "operation-finished");
2516 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2518 ModestMsgViewWindowPrivate *priv;
2519 TnyList *selected_attachments = NULL;
2521 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2522 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2524 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2526 return selected_attachments;
2532 guint banner_idle_id;
2533 } DecodeAsyncHelper;
2536 decode_async_banner_idle (gpointer user_data)
2538 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2540 helper->banner_idle_id = 0;
2541 helper->banner = hildon_banner_show_animation (NULL, NULL, _("mail_me_opening"));
2542 g_object_ref (helper->banner);
2548 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2554 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2556 if (helper->banner_idle_id > 0) {
2557 g_source_remove (helper->banner_idle_id);
2558 helper->banner_idle_id = 0;
2560 if (helper->banner) {
2561 gtk_widget_destroy (helper->banner);
2563 if (cancelled || err) {
2564 modest_platform_information_banner (NULL, NULL,
2565 _("mail_ib_file_operation_failed"));
2569 /* make the file read-only */
2570 g_chmod(helper->filepath, 0444);
2572 /* Activate the file */
2573 modest_platform_activate_file (helper->filepath, modest_tny_mime_part_get_content_type (mime_part));
2577 g_free (helper->filepath);
2578 g_object_unref (helper->banner);
2579 g_slice_free (DecodeAsyncHelper, helper);
2583 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2584 TnyMimePart *mime_part)
2586 ModestMsgViewWindowPrivate *priv;
2587 const gchar *msg_uid;
2588 gchar *attachment_uid = NULL;
2589 gint attachment_index = 0;
2590 TnyList *attachments;
2591 TnyMimePart *window_msg;
2593 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2594 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2595 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2597 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2598 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2599 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2600 g_object_unref (attachments);
2602 if (msg_uid && attachment_index >= 0) {
2603 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2606 if (mime_part == NULL) {
2607 gboolean error = FALSE;
2608 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2609 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2611 } else if (tny_list_get_length (selected_attachments) > 1) {
2612 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2616 iter = tny_list_create_iterator (selected_attachments);
2617 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2618 g_object_unref (iter);
2620 if (selected_attachments)
2621 g_object_unref (selected_attachments);
2626 g_object_ref (mime_part);
2629 if (tny_mime_part_is_purged (mime_part)) {
2630 g_object_unref (mime_part);
2634 /* we also check for mime_part == priv->msg, as this means it's a direct attachment
2635 * shown as attachment, so it should behave as a file */
2636 window_msg = TNY_MIME_PART (tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view)));
2637 if ((!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) ||
2638 mime_part == window_msg) {
2639 gchar *filepath = NULL;
2640 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2641 gboolean show_error_banner = FALSE;
2642 TnyFsStream *temp_stream = NULL;
2643 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2646 if (temp_stream != NULL) {
2647 DecodeAsyncHelper *helper = g_slice_new (DecodeAsyncHelper);
2648 helper->filepath = g_strdup (filepath);
2649 helper->banner = NULL;
2650 helper->banner_idle_id = g_timeout_add (1000, decode_async_banner_idle, helper);
2651 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2652 on_decode_to_stream_async_handler,
2655 g_object_unref (temp_stream);
2656 /* NOTE: files in the temporary area will be automatically
2657 * cleaned after some time if they are no longer in use */
2660 const gchar *content_type;
2661 /* the file may already exist but it isn't writable,
2662 * let's try to open it anyway */
2663 content_type = modest_tny_mime_part_get_content_type (mime_part);
2664 modest_platform_activate_file (filepath, content_type);
2666 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2667 show_error_banner = TRUE;
2672 if (show_error_banner)
2673 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2674 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2675 ModestWindowMgr *mgr;
2676 ModestWindow *msg_win = NULL;
2677 TnyMsg *current_msg;
2681 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2682 mgr = modest_runtime_get_window_mgr ();
2683 header = tny_msg_get_header (TNY_MSG (current_msg));
2684 found = modest_window_mgr_find_registered_message_uid (mgr,
2689 g_warning ("window for this body is already being created");
2692 /* it's not found, so create a new window for it */
2693 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2694 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2695 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2697 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2699 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part),
2700 account, mailbox, attachment_uid);
2702 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2703 modest_window_get_zoom (MODEST_WINDOW (window)));
2704 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2705 gtk_widget_show_all (GTK_WIDGET (msg_win));
2707 gtk_widget_destroy (GTK_WIDGET (msg_win));
2709 g_object_unref (current_msg);
2711 /* message attachment */
2712 TnyHeader *header = NULL;
2713 ModestWindowMgr *mgr;
2714 ModestWindow *msg_win = NULL;
2717 header = tny_msg_get_header (TNY_MSG (mime_part));
2718 mgr = modest_runtime_get_window_mgr ();
2719 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2722 if (msg_win) /* there is already a window for this uid; top it */
2723 gtk_window_present (GTK_WINDOW(msg_win));
2725 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2726 * thus, we don't do anything */
2727 g_warning ("window for is already being created");
2729 /* it's not found, so create a new window for it */
2730 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2731 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2733 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2734 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account,
2735 NULL, attachment_uid);
2736 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2737 modest_window_get_zoom (MODEST_WINDOW (window)));
2738 modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window));
2739 gtk_widget_show_all (GTK_WIDGET (msg_win));
2742 g_object_unref (window_msg);
2743 g_object_unref (mime_part);
2756 GnomeVFSResult result;
2759 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2760 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2761 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2762 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2765 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2769 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2770 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2771 g_free (pair->filename);
2772 g_object_unref (pair->part);
2773 g_slice_free (SaveMimePartPair, pair);
2775 g_list_free (info->pairs);
2778 gtk_widget_destroy (info->banner);
2779 g_slice_free (SaveMimePartInfo, info);
2784 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2786 if (info->pairs != NULL) {
2787 save_mime_part_to_file (info);
2789 /* This is a GDK lock because we are an idle callback and
2790 * hildon_banner_show_information is or does Gtk+ code */
2792 gdk_threads_enter (); /* CHECKED */
2793 save_mime_part_info_free (info, TRUE);
2794 if (info->result == GNOME_VFS_OK) {
2795 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2796 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
2797 hildon_banner_show_information (NULL, NULL,
2798 _KR("cerm_device_memory_full"));
2800 hildon_banner_show_information (NULL, NULL,
2801 _("mail_ib_file_operation_failed"));
2803 gdk_threads_leave (); /* CHECKED */
2810 save_mime_part_to_file (SaveMimePartInfo *info)
2812 GnomeVFSHandle *handle;
2814 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2816 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2817 if (info->result == GNOME_VFS_OK) {
2818 GError *error = NULL;
2819 stream = tny_vfs_stream_new (handle);
2820 if (tny_mime_part_decode_to_stream (pair->part, stream, &error) < 0) {
2821 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
2823 info->result = GNOME_VFS_ERROR_IO;
2825 g_object_unref (G_OBJECT (stream));
2826 g_object_unref (pair->part);
2827 g_slice_free (SaveMimePartPair, pair);
2828 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2830 g_warning ("modest: could not create save attachment %s: %s\n", pair->filename, gnome_vfs_result_to_string (info->result));
2831 save_mime_part_info_free (info, FALSE);
2834 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2839 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2841 gboolean is_ok = TRUE;
2842 gint replaced_files = 0;
2843 const GList *files = info->pairs;
2846 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2847 SaveMimePartPair *pair = iter->data;
2848 if (modest_utils_file_exists (pair->filename)) {
2852 if (replaced_files) {
2853 GtkWidget *confirm_overwrite_dialog;
2854 const gchar *message = (replaced_files == 1) ?
2855 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2856 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2857 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2860 gtk_widget_destroy (confirm_overwrite_dialog);
2864 save_mime_part_info_free (info, TRUE);
2866 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2867 _CS("sfil_ib_saving"));
2868 info->banner = banner;
2869 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2875 save_attachments_response (GtkDialog *dialog,
2879 TnyList *mime_parts;
2881 GList *files_to_save = NULL;
2883 mime_parts = TNY_LIST (user_data);
2885 if (arg1 != GTK_RESPONSE_OK)
2888 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
2890 if (!modest_utils_folder_writable (chooser_uri)) {
2891 hildon_banner_show_information
2892 (NULL, NULL, _FM("sfil_ib_readonly_location"));
2896 iter = tny_list_create_iterator (mime_parts);
2897 while (!tny_iterator_is_done (iter)) {
2898 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2900 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
2901 !tny_mime_part_is_purged (mime_part) &&
2902 (tny_mime_part_get_filename (mime_part) != NULL)) {
2903 SaveMimePartPair *pair;
2905 pair = g_slice_new0 (SaveMimePartPair);
2907 if (tny_list_get_length (mime_parts) > 1) {
2909 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
2910 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
2913 pair->filename = g_strdup (chooser_uri);
2915 pair->part = mime_part;
2916 files_to_save = g_list_prepend (files_to_save, pair);
2918 tny_iterator_next (iter);
2920 g_object_unref (iter);
2922 g_free (chooser_uri);
2924 if (files_to_save != NULL) {
2925 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2926 info->pairs = files_to_save;
2927 info->result = TRUE;
2928 save_mime_parts_to_file_with_checks (info);
2932 /* Free and close the dialog */
2933 g_object_unref (mime_parts);
2934 gtk_widget_destroy (GTK_WIDGET (dialog));
2938 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, TnyList *mime_parts)
2940 ModestMsgViewWindowPrivate *priv;
2941 GtkWidget *save_dialog = NULL;
2942 gchar *folder = NULL;
2943 gchar *filename = NULL;
2944 gchar *save_multiple_str = NULL;
2947 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2948 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2950 if (mime_parts == NULL) {
2951 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2952 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0)
2955 g_object_ref (mime_parts);
2958 window_msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2959 /* prepare dialog */
2960 if (tny_list_get_length (mime_parts) == 1) {
2962 /* only one attachment selected */
2963 iter = tny_list_create_iterator (mime_parts);
2964 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2965 g_object_unref (iter);
2966 if (!modest_tny_mime_part_is_msg (mime_part) &&
2967 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
2968 !tny_mime_part_is_purged (mime_part)) {
2969 filename = g_strdup (tny_mime_part_get_filename (mime_part));
2971 /* TODO: show any error? */
2972 g_warning ("Tried to save a non-file attachment");
2973 g_object_unref (mime_parts);
2976 g_object_unref (mime_part);
2978 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2979 tny_list_get_length (mime_parts));
2981 g_object_unref (window_msg);
2983 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2984 GTK_FILE_CHOOSER_ACTION_SAVE);
2987 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2988 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2993 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2998 /* if multiple, set multiple string */
2999 if (save_multiple_str) {
3000 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3001 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
3004 /* We must run this asynchronously, because the hildon dialog
3005 performs a gtk_dialog_run by itself which leads to gdk
3007 g_signal_connect (save_dialog, "response",
3008 G_CALLBACK (save_attachments_response), mime_parts);
3010 gtk_widget_show_all (save_dialog);
3014 show_remove_attachment_information (gpointer userdata)
3016 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3017 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3019 /* We're outside the main lock */
3020 gdk_threads_enter ();
3022 if (priv->remove_attachment_banner != NULL) {
3023 gtk_widget_destroy (priv->remove_attachment_banner);
3024 g_object_unref (priv->remove_attachment_banner);
3027 priv->remove_attachment_banner = g_object_ref (
3028 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
3030 gdk_threads_leave ();
3036 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3038 ModestMsgViewWindowPrivate *priv;
3039 TnyList *mime_parts = NULL;
3040 gchar *confirmation_message;
3046 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3047 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3050 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3052 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
3054 /* Remove already purged messages from mime parts list */
3055 iter = tny_list_create_iterator (mime_parts);
3056 while (!tny_iterator_is_done (iter)) {
3057 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3058 tny_iterator_next (iter);
3059 if (tny_mime_part_is_purged (part)) {
3060 tny_list_remove (mime_parts, (GObject *) part);
3062 g_object_unref (part);
3064 g_object_unref (iter);
3066 if (tny_list_get_length (mime_parts) == 0) {
3067 g_object_unref (mime_parts);
3071 n_attachments = tny_list_get_length (mime_parts);
3072 if (n_attachments == 1) {
3076 iter = tny_list_create_iterator (mime_parts);
3077 part = (TnyMimePart *) tny_iterator_get_current (iter);
3078 g_object_unref (iter);
3079 if (modest_tny_mime_part_is_msg (part)) {
3081 header = tny_msg_get_header (TNY_MSG (part));
3082 filename = tny_header_dup_subject (header);
3083 g_object_unref (header);
3084 if (filename == NULL)
3085 filename = g_strdup (_("mail_va_no_subject"));
3087 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3089 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3091 g_object_unref (part);
3093 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3094 "mcen_nc_purge_files_text",
3095 n_attachments), n_attachments);
3097 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3098 confirmation_message);
3099 g_free (confirmation_message);
3101 if (response != GTK_RESPONSE_OK) {
3102 g_object_unref (mime_parts);
3106 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3108 iter = tny_list_create_iterator (mime_parts);
3109 while (!tny_iterator_is_done (iter)) {
3112 part = (TnyMimePart *) tny_iterator_get_current (iter);
3113 tny_mime_part_set_purged (TNY_MIME_PART (part));
3114 g_object_unref (part);
3115 tny_iterator_next (iter);
3117 g_object_unref (iter);
3119 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3120 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3121 tny_msg_rewrite_cache (msg);
3122 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3123 g_object_unref (msg);
3125 g_object_unref (mime_parts);
3127 if (priv->purge_timeout > 0) {
3128 g_source_remove (priv->purge_timeout);
3129 priv->purge_timeout = 0;
3132 if (priv->remove_attachment_banner) {
3133 gtk_widget_destroy (priv->remove_attachment_banner);
3134 g_object_unref (priv->remove_attachment_banner);
3135 priv->remove_attachment_banner = NULL;
3143 update_window_title (ModestMsgViewWindow *window)
3145 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3147 TnyHeader *header = NULL;
3148 gchar *subject = NULL;
3150 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3152 if (priv->other_body) {
3155 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3157 g_strstrip (description);
3158 subject = description;
3160 } else if (msg != NULL) {
3161 header = tny_msg_get_header (msg);
3162 subject = tny_header_dup_subject (header);
3163 g_object_unref (header);
3164 g_object_unref (msg);
3167 if ((subject == NULL)||(subject[0] == '\0')) {
3169 subject = g_strdup (_("mail_va_no_subject"));
3172 gtk_window_set_title (GTK_WINDOW (window), subject);
3176 static void on_move_focus (GtkWidget *widget,
3177 GtkDirectionType direction,
3180 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3184 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3186 GnomeVFSResult result;
3187 GnomeVFSHandle *handle = NULL;
3188 GnomeVFSFileInfo *info = NULL;
3191 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3192 if (result != GNOME_VFS_OK) {
3197 info = gnome_vfs_file_info_new ();
3198 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3199 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3200 /* We put a "safe" default size for going to cache */
3201 *expected_size = (300*1024);
3203 *expected_size = info->size;
3205 gnome_vfs_file_info_unref (info);
3207 stream = tny_vfs_stream_new (handle);
3216 TnyStream *output_stream;
3217 GtkWidget *msg_view;
3221 on_fetch_image_idle_refresh_view (gpointer userdata)
3224 FetchImageData *fidata = (FetchImageData *) userdata;
3225 g_message ("REFRESH VIEW");
3226 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3227 g_message ("QUEUING DRAW");
3228 gtk_widget_queue_draw (fidata->msg_view);
3230 g_object_unref (fidata->msg_view);
3231 g_slice_free (FetchImageData, fidata);
3236 on_fetch_image_thread (gpointer userdata)
3238 FetchImageData *fidata = (FetchImageData *) userdata;
3239 TnyStreamCache *cache;
3240 TnyStream *cache_stream;
3242 cache = modest_runtime_get_images_cache ();
3243 cache_stream = tny_stream_cache_get_stream (cache, fidata->cache_id, (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream, (gpointer) fidata->uri);
3244 g_free (fidata->cache_id);
3245 g_free (fidata->uri);
3247 if (cache_stream != NULL) {
3248 tny_stream_write_to_stream (cache_stream, fidata->output_stream);
3249 tny_stream_close (cache_stream);
3250 g_object_unref (cache_stream);
3253 tny_stream_close (fidata->output_stream);
3254 g_object_unref (fidata->output_stream);
3257 gdk_threads_enter ();
3258 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3259 gdk_threads_leave ();
3265 on_fetch_image (ModestMsgView *msgview,
3268 ModestMsgViewWindow *window)
3270 const gchar *current_account;
3271 ModestMsgViewWindowPrivate *priv;
3272 FetchImageData *fidata;
3274 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3276 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3278 fidata = g_slice_new0 (FetchImageData);
3279 fidata->msg_view = g_object_ref (msgview);
3280 fidata->uri = g_strdup (uri);
3281 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3282 fidata->output_stream = g_object_ref (stream);
3284 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3285 g_object_unref (fidata->output_stream);
3286 g_free (fidata->cache_id);
3287 g_free (fidata->uri);
3288 g_object_unref (fidata->msg_view);
3289 g_slice_free (FetchImageData, fidata);
3290 tny_stream_close (stream);
3298 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3300 modest_ui_actions_on_add_to_contacts (NULL, MODEST_WINDOW (self));
3305 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
3307 ModestMsgViewWindowPrivate *priv;
3308 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3310 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
3314 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
3316 ModestMsgViewWindowPrivate *priv;
3317 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3319 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
3321 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
3325 modest_msg_view_window_reload (ModestMsgViewWindow *self)
3327 ModestMsgViewWindowPrivate *priv;
3330 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
3332 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3333 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
3335 if (!message_reader (self, priv, header, priv->row_reference)) {
3336 g_warning ("Shouldn't happen, trying to reload a message failed");
3339 g_object_unref (header);