1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include <tny-error.h>
37 #include "modest-marshal.h"
38 #include "modest-platform.h"
39 #include <modest-utils.h>
40 #include <modest-maemo-utils.h>
41 #include <modest-tny-msg.h>
42 #include <modest-msg-view-window.h>
43 #include <modest-main-window-ui.h>
44 #include "modest-msg-view-window-ui-dimming.h"
45 #include <modest-widget-memory.h>
46 #include <modest-progress-object.h>
47 #include <modest-runtime.h>
48 #include <modest-window-priv.h>
49 #include <modest-tny-folder.h>
50 #include <modest-text-utils.h>
51 #include <modest-account-mgr-helpers.h>
52 #include <hildon/hildon-pannable-area.h>
53 #include <hildon/hildon-picker-dialog.h>
54 #include <hildon/hildon-app-menu.h>
55 #include "modest-defs.h"
56 #include "modest-hildon-includes.h"
57 #include "modest-ui-dimming-manager.h"
58 #include <gdk/gdkkeysyms.h>
59 #include <modest-tny-account.h>
60 #include <modest-mime-part-view.h>
61 #include <modest-isearch-view.h>
62 #include <modest-tny-mime-part.h>
63 #include <modest-address-book.h>
66 #include <glib/gstdio.h>
67 #include <modest-debug.h>
68 #include <modest-header-window.h>
70 #define MYDOCS_ENV "MYDOCSDIR"
71 #define DOCS_FOLDER ".documents"
73 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
74 struct _ModestMsgViewWindowPrivate {
77 GtkWidget *main_scroll;
78 GtkWidget *find_toolbar;
81 /* Progress observers */
82 GSList *progress_widgets;
85 GtkWidget *prev_toolitem;
86 GtkWidget *next_toolitem;
87 gboolean progress_hint;
90 /* Optimized view enabled */
91 gboolean optimized_view;
93 /* Whether this was created via the *_new_for_search_result() function. */
94 gboolean is_search_result;
96 /* Whether the message is in outbox */
99 /* A reference to the @model of the header view
100 * to allow selecting previous/next messages,
101 * if the message is currently selected in the header view.
103 const gchar *header_folder_id;
104 GtkTreeModel *header_model;
105 GtkTreeRowReference *row_reference;
106 GtkTreeRowReference *next_row_reference;
108 gulong clipboard_change_handler;
109 gulong queue_change_handler;
110 gulong account_removed_handler;
111 gulong row_changed_handler;
112 gulong row_deleted_handler;
113 gulong row_inserted_handler;
114 gulong rows_reordered_handler;
117 GtkWidget *remove_attachment_banner;
120 gboolean is_other_body;
125 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
126 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
127 static void modest_header_view_observer_init(
128 ModestHeaderViewObserverIface *iface_class);
129 static void modest_msg_view_window_finalize (GObject *obj);
130 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
132 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
133 ModestMsgViewWindow *obj);
134 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
135 ModestMsgViewWindow *obj);
137 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
139 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
140 static void modest_msg_view_window_set_zoom (ModestWindow *window,
142 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
143 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
144 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
147 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
149 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
150 gboolean show_toolbar);
152 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
154 ModestMsgViewWindow *window);
156 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
159 ModestMsgViewWindow *window);
161 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
163 ModestMsgViewWindow *window);
165 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
166 GtkTreePath *tree_path,
167 GtkTreeIter *tree_iter,
168 ModestMsgViewWindow *window);
170 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
174 ModestMsgViewWindow *window);
176 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
178 const gchar *tny_folder_id);
180 static void on_queue_changed (ModestMailOperationQueue *queue,
181 ModestMailOperation *mail_op,
182 ModestMailOperationQueueNotification type,
183 ModestMsgViewWindow *self);
185 static void on_account_removed (TnyAccountStore *account_store,
189 static void on_move_focus (GtkWidget *widget,
190 GtkDirectionType direction,
193 static void view_msg_cb (ModestMailOperation *mail_op,
200 static void set_progress_hint (ModestMsgViewWindow *self,
203 static void update_window_title (ModestMsgViewWindow *window);
205 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
206 static void init_window (ModestMsgViewWindow *obj);
208 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
210 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
212 static gboolean on_fetch_image (ModestMsgView *msgview,
215 ModestMsgViewWindow *window);
217 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
218 GtkScrollType scroll_type,
221 static gboolean message_reader (ModestMsgViewWindow *window,
222 ModestMsgViewWindowPrivate *priv,
224 GtkTreeRowReference *row_reference);
226 static void setup_menu (ModestMsgViewWindow *self);
227 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
232 /* list my signals */
239 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
240 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
244 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
245 MODEST_TYPE_MSG_VIEW_WINDOW, \
246 ModestMsgViewWindowPrivate))
248 static GtkWindowClass *parent_class = NULL;
250 /* uncomment the following if you have defined any signals */
251 static guint signals[LAST_SIGNAL] = {0};
254 modest_msg_view_window_get_type (void)
256 static GType my_type = 0;
258 static const GTypeInfo my_info = {
259 sizeof(ModestMsgViewWindowClass),
260 NULL, /* base init */
261 NULL, /* base finalize */
262 (GClassInitFunc) modest_msg_view_window_class_init,
263 NULL, /* class finalize */
264 NULL, /* class data */
265 sizeof(ModestMsgViewWindow),
267 (GInstanceInitFunc) modest_msg_view_window_init,
270 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
271 "ModestMsgViewWindow",
274 static const GInterfaceInfo modest_header_view_observer_info =
276 (GInterfaceInitFunc) modest_header_view_observer_init,
277 NULL, /* interface_finalize */
278 NULL /* interface_data */
281 g_type_add_interface_static (my_type,
282 MODEST_TYPE_HEADER_VIEW_OBSERVER,
283 &modest_header_view_observer_info);
289 save_state (ModestWindow *self)
291 modest_widget_memory_save (modest_runtime_get_conf (),
293 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
297 gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
298 GtkScrollType scroll_type,
302 ModestMsgViewWindowPrivate *priv;
303 gboolean return_value;
305 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
306 g_signal_emit_by_name (priv->main_scroll, "scroll-child", scroll_type, horizontal, &return_value);
311 add_scroll_binding (GtkBindingSet *binding_set,
313 GtkScrollType scroll)
315 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
317 gtk_binding_entry_add_signal (binding_set, keyval, 0,
319 GTK_TYPE_SCROLL_TYPE, scroll,
320 G_TYPE_BOOLEAN, FALSE);
321 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
323 GTK_TYPE_SCROLL_TYPE, scroll,
324 G_TYPE_BOOLEAN, FALSE);
328 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
330 GObjectClass *gobject_class;
331 HildonWindowClass *hildon_window_class;
332 ModestWindowClass *modest_window_class;
333 GtkBindingSet *binding_set;
335 gobject_class = (GObjectClass*) klass;
336 hildon_window_class = (HildonWindowClass *) klass;
337 modest_window_class = (ModestWindowClass *) klass;
339 parent_class = g_type_class_peek_parent (klass);
340 gobject_class->finalize = modest_msg_view_window_finalize;
342 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
343 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
344 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
345 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
346 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
347 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
349 modest_window_class->save_state_func = save_state;
351 klass->scroll_child = modest_msg_view_window_scroll_child;
353 signals[MSG_CHANGED_SIGNAL] =
354 g_signal_new ("msg-changed",
355 G_TYPE_FROM_CLASS (gobject_class),
357 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
359 modest_marshal_VOID__POINTER_POINTER,
360 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
362 signals[SCROLL_CHILD_SIGNAL] =
363 g_signal_new ("scroll-child",
364 G_TYPE_FROM_CLASS (gobject_class),
365 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
366 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
368 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
369 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
371 binding_set = gtk_binding_set_by_class (klass);
372 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
373 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
374 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
375 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
376 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
377 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
379 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
383 static void modest_header_view_observer_init(
384 ModestHeaderViewObserverIface *iface_class)
386 iface_class->update_func = modest_msg_view_window_update_model_replaced;
390 modest_msg_view_window_init (ModestMsgViewWindow *obj)
392 ModestMsgViewWindowPrivate *priv;
393 ModestWindowPrivate *parent_priv = NULL;
394 GtkActionGroup *action_group = NULL;
395 GError *error = NULL;
396 GdkPixbuf *window_icon;
398 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
399 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
400 parent_priv->ui_manager = gtk_ui_manager_new();
402 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
403 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
405 /* Add common actions */
406 gtk_action_group_add_actions (action_group,
407 modest_action_entries,
408 G_N_ELEMENTS (modest_action_entries),
410 gtk_action_group_add_toggle_actions (action_group,
411 msg_view_toggle_action_entries,
412 G_N_ELEMENTS (msg_view_toggle_action_entries),
415 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
416 g_object_unref (action_group);
418 /* Load the UI definition */
419 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
422 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
423 g_error_free (error);
428 /* Add accelerators */
429 gtk_window_add_accel_group (GTK_WINDOW (obj),
430 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
432 priv->is_search_result = FALSE;
433 priv->is_outbox = FALSE;
435 priv->msg_view = NULL;
436 priv->header_model = NULL;
437 priv->header_folder_id = NULL;
438 priv->clipboard_change_handler = 0;
439 priv->queue_change_handler = 0;
440 priv->account_removed_handler = 0;
441 priv->row_changed_handler = 0;
442 priv->row_deleted_handler = 0;
443 priv->row_inserted_handler = 0;
444 priv->rows_reordered_handler = 0;
445 priv->progress_hint = FALSE;
446 priv->fetching_images = 0;
448 priv->optimized_view = FALSE;
449 priv->purge_timeout = 0;
450 priv->remove_attachment_banner = NULL;
451 priv->msg_uid = NULL;
452 priv->is_other_body = FALSE;
454 priv->sighandlers = NULL;
457 init_window (MODEST_MSG_VIEW_WINDOW(obj));
459 /* Set window icon */
460 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
462 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
463 g_object_unref (window_icon);
466 hildon_program_add_window (hildon_program_get_instance(),
473 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
475 ModestMsgViewWindowPrivate *priv = NULL;
477 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
479 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
481 set_progress_hint (self, TRUE);
487 update_progress_hint (ModestMsgViewWindow *self)
489 ModestMsgViewWindowPrivate *priv;
490 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
492 if (GTK_WIDGET_VISIBLE (self)) {
493 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self),
494 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
499 set_progress_hint (ModestMsgViewWindow *self,
502 ModestWindowPrivate *parent_priv;
503 ModestMsgViewWindowPrivate *priv;
505 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
507 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
508 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
510 /* Sets current progress hint */
511 priv->progress_hint = enabled;
513 update_progress_hint (self);
519 init_window (ModestMsgViewWindow *obj)
521 GtkWidget *main_vbox;
522 ModestMsgViewWindowPrivate *priv;
524 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
526 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
527 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
528 main_vbox = gtk_vbox_new (FALSE, 6);
529 priv->main_scroll = hildon_pannable_area_new ();
530 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
531 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
532 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
534 priv->find_toolbar = hildon_find_toolbar_new (NULL);
535 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
536 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
538 /* NULL-ize fields if the window is destroyed */
539 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
541 gtk_widget_show_all (GTK_WIDGET(main_vbox));
545 modest_msg_view_window_disconnect_signals (ModestWindow *self)
547 ModestMsgViewWindowPrivate *priv;
548 GtkWidget *header_view = NULL;
549 GtkWindow *parent_window = NULL;
551 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
553 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
554 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
555 priv->clipboard_change_handler))
556 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
557 priv->clipboard_change_handler);
559 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
560 priv->queue_change_handler))
561 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
562 priv->queue_change_handler);
564 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
565 priv->account_removed_handler))
566 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
567 priv->account_removed_handler);
569 if (priv->header_model) {
570 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
571 priv->row_changed_handler))
572 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
573 priv->row_changed_handler);
575 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
576 priv->row_deleted_handler))
577 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
578 priv->row_deleted_handler);
580 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
581 priv->row_inserted_handler))
582 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
583 priv->row_inserted_handler);
585 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
586 priv->rows_reordered_handler))
587 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
588 priv->rows_reordered_handler);
591 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
592 priv->sighandlers = NULL;
594 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
595 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
596 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
598 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
599 MODEST_HEADER_VIEW_OBSERVER(self));
605 modest_msg_view_window_finalize (GObject *obj)
607 ModestMsgViewWindowPrivate *priv;
609 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
611 /* Sanity check: shouldn't be needed, the window mgr should
612 call this function before */
613 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
615 if (priv->header_model != NULL) {
616 g_object_unref (priv->header_model);
617 priv->header_model = NULL;
620 if (priv->remove_attachment_banner) {
621 gtk_widget_destroy (priv->remove_attachment_banner);
622 g_object_unref (priv->remove_attachment_banner);
623 priv->remove_attachment_banner = NULL;
626 if (priv->purge_timeout > 0) {
627 g_source_remove (priv->purge_timeout);
628 priv->purge_timeout = 0;
631 if (priv->row_reference) {
632 gtk_tree_row_reference_free (priv->row_reference);
633 priv->row_reference = NULL;
636 if (priv->next_row_reference) {
637 gtk_tree_row_reference_free (priv->next_row_reference);
638 priv->next_row_reference = NULL;
642 g_free (priv->msg_uid);
643 priv->msg_uid = NULL;
646 G_OBJECT_CLASS(parent_class)->finalize (obj);
650 select_next_valid_row (GtkTreeModel *model,
651 GtkTreeRowReference **row_reference,
655 GtkTreeIter tmp_iter;
657 GtkTreePath *next = NULL;
658 gboolean retval = FALSE, finished;
660 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
662 path = gtk_tree_row_reference_get_path (*row_reference);
663 gtk_tree_model_get_iter (model, &tmp_iter, path);
664 gtk_tree_row_reference_free (*row_reference);
665 *row_reference = NULL;
669 TnyHeader *header = NULL;
671 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
672 gtk_tree_model_get (model, &tmp_iter,
673 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
677 if (msg_is_visible (header, is_outbox)) {
678 next = gtk_tree_model_get_path (model, &tmp_iter);
679 *row_reference = gtk_tree_row_reference_new (model, next);
680 gtk_tree_path_free (next);
684 g_object_unref (header);
687 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
688 next = gtk_tree_model_get_path (model, &tmp_iter);
690 /* Ensure that we are not selecting the same */
691 if (gtk_tree_path_compare (path, next) != 0) {
692 gtk_tree_model_get (model, &tmp_iter,
693 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
696 if (msg_is_visible (header, is_outbox)) {
697 *row_reference = gtk_tree_row_reference_new (model, next);
701 g_object_unref (header);
705 /* If we ended up in the same message
706 then there is no valid next
710 gtk_tree_path_free (next);
712 /* If there are no more messages and we don't
713 want to start again in the first one then
714 there is no valid next message */
720 gtk_tree_path_free (path);
725 /* TODO: This should be in _init(), with the parameters as properties. */
727 modest_msg_view_window_construct (ModestMsgViewWindow *self,
728 const gchar *modest_account_name,
729 const gchar *mailbox,
730 const gchar *msg_uid)
733 ModestMsgViewWindowPrivate *priv = NULL;
734 ModestWindowPrivate *parent_priv = NULL;
735 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
736 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
738 obj = G_OBJECT (self);
739 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
740 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
742 priv->msg_uid = g_strdup (msg_uid);
745 parent_priv->menubar = NULL;
747 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
748 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
751 /* Add common dimming rules */
752 modest_dimming_rules_group_add_rules (toolbar_rules_group,
753 modest_msg_view_toolbar_dimming_entries,
754 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
755 MODEST_WINDOW (self));
756 modest_dimming_rules_group_add_rules (clipboard_rules_group,
757 modest_msg_view_clipboard_dimming_entries,
758 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
759 MODEST_WINDOW (self));
761 /* Insert dimming rules group for this window */
762 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
763 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
764 g_object_unref (toolbar_rules_group);
765 g_object_unref (clipboard_rules_group);
767 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
769 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);
770 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
771 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
772 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
773 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
774 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
775 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
776 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
777 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
778 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
779 G_CALLBACK (modest_ui_actions_on_details), obj);
780 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
781 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
782 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
783 G_CALLBACK (on_fetch_image), obj);
785 g_signal_connect (G_OBJECT (obj), "key-release-event",
786 G_CALLBACK (modest_msg_view_window_key_event),
789 g_signal_connect (G_OBJECT (obj), "key-press-event",
790 G_CALLBACK (modest_msg_view_window_key_event),
793 g_signal_connect (G_OBJECT (obj), "move-focus",
794 G_CALLBACK (on_move_focus), obj);
796 g_signal_connect (G_OBJECT (obj), "map-event",
797 G_CALLBACK (_modest_msg_view_window_map_event),
800 /* Mail Operation Queue */
801 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
803 G_CALLBACK (on_queue_changed),
806 /* Account manager */
807 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
809 G_CALLBACK(on_account_removed),
812 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
813 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
815 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
816 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
817 priv->last_search = NULL;
819 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
821 /* Init the clipboard actions dim status */
822 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
824 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
829 /* FIXME: parameter checks */
831 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
832 const gchar *modest_account_name,
833 const gchar *mailbox,
834 const gchar *msg_uid,
836 GtkTreeRowReference *row_reference)
838 ModestMsgViewWindow *window = NULL;
839 ModestMsgViewWindowPrivate *priv = NULL;
840 TnyFolder *header_folder = NULL;
841 ModestHeaderView *header_view = NULL;
842 ModestWindowMgr *mgr = NULL;
845 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
848 mgr = modest_runtime_get_window_mgr ();
849 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
850 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
852 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
854 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
856 /* Remember the message list's TreeModel so we can detect changes
857 * and change the list selection when necessary: */
858 header_folder = modest_header_view_get_folder (header_view);
860 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
861 TNY_FOLDER_TYPE_OUTBOX);
862 priv->header_folder_id = tny_folder_get_id (header_folder);
863 g_object_unref(header_folder);
866 /* Setup row references and connect signals */
867 priv->header_model = g_object_ref (model);
870 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
871 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
872 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
874 priv->row_reference = NULL;
875 priv->next_row_reference = NULL;
878 /* Connect signals */
879 priv->row_changed_handler =
880 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
881 G_CALLBACK(modest_msg_view_window_on_row_changed),
883 priv->row_deleted_handler =
884 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
885 G_CALLBACK(modest_msg_view_window_on_row_deleted),
887 priv->row_inserted_handler =
888 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
889 G_CALLBACK(modest_msg_view_window_on_row_inserted),
891 priv->rows_reordered_handler =
892 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
893 G_CALLBACK(modest_msg_view_window_on_row_reordered),
896 if (header_view != NULL){
897 modest_header_view_add_observer(header_view,
898 MODEST_HEADER_VIEW_OBSERVER(window));
901 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
902 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
904 /* gtk_widget_show_all (GTK_WIDGET (window)); */
905 modest_msg_view_window_update_priority (window);
906 /* Check dimming rules */
907 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
908 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
909 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
911 return MODEST_WINDOW(window);
915 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
916 const gchar *modest_account_name,
917 const gchar *mailbox,
918 const gchar *msg_uid,
919 GtkTreeRowReference *row_reference)
921 ModestMsgViewWindow *window = NULL;
922 ModestMsgViewWindowPrivate *priv = NULL;
923 TnyFolder *header_folder = NULL;
924 ModestWindowMgr *mgr = NULL;
928 mgr = modest_runtime_get_window_mgr ();
929 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
930 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
932 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
934 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
936 /* Remember the message list's TreeModel so we can detect changes
937 * and change the list selection when necessary: */
939 if (header_view != NULL){
940 header_folder = modest_header_view_get_folder(header_view);
941 /* This could happen if the header folder was
942 unseleted before opening this msg window (for
943 example if the user selects an account in the
944 folder view of the main window */
946 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
947 TNY_FOLDER_TYPE_OUTBOX);
948 priv->header_folder_id = tny_folder_get_id(header_folder);
949 g_object_unref(header_folder);
953 /* Setup row references and connect signals */
954 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
955 g_object_ref (priv->header_model);
958 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
959 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
960 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
962 priv->row_reference = NULL;
963 priv->next_row_reference = NULL;
966 /* Connect signals */
967 priv->row_changed_handler =
968 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
969 G_CALLBACK(modest_msg_view_window_on_row_changed),
971 priv->row_deleted_handler =
972 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
973 G_CALLBACK(modest_msg_view_window_on_row_deleted),
975 priv->row_inserted_handler =
976 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
977 G_CALLBACK(modest_msg_view_window_on_row_inserted),
979 priv->rows_reordered_handler =
980 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
981 G_CALLBACK(modest_msg_view_window_on_row_reordered),
984 if (header_view != NULL){
985 modest_header_view_add_observer(header_view,
986 MODEST_HEADER_VIEW_OBSERVER(window));
989 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
991 path = gtk_tree_row_reference_get_path (row_reference);
992 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
994 gtk_tree_model_get (priv->header_model, &iter,
995 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
997 message_reader (window, priv, header, row_reference);
998 g_object_unref (header);
1000 gtk_tree_path_free (path);
1002 /* Check dimming rules */
1003 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1004 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1005 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1007 return MODEST_WINDOW(window);
1011 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1012 const gchar *modest_account_name,
1013 const gchar *mailbox,
1014 const gchar *msg_uid)
1016 ModestMsgViewWindow *window = NULL;
1017 ModestMsgViewWindowPrivate *priv = NULL;
1018 ModestWindowMgr *mgr = NULL;
1020 mgr = modest_runtime_get_window_mgr ();
1021 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1022 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1023 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1025 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1027 /* Remember that this is a search result,
1028 * so we can disable some UI appropriately: */
1029 priv->is_search_result = TRUE;
1031 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1033 update_window_title (window);
1034 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1035 modest_msg_view_window_update_priority (window);
1037 /* Check dimming rules */
1038 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1039 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1040 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1042 return MODEST_WINDOW(window);
1046 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1047 TnyMimePart *other_body,
1048 const gchar *modest_account_name,
1049 const gchar *mailbox,
1050 const gchar *msg_uid)
1052 GObject *obj = NULL;
1053 ModestMsgViewWindowPrivate *priv;
1054 ModestWindowMgr *mgr = NULL;
1056 g_return_val_if_fail (msg, NULL);
1057 mgr = modest_runtime_get_window_mgr ();
1058 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1059 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1060 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1061 modest_account_name, mailbox, msg_uid);
1064 priv->is_other_body = TRUE;
1065 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1067 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1069 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1071 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1073 /* Check dimming rules */
1074 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1075 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1076 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1078 return MODEST_WINDOW(obj);
1082 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1083 const gchar *modest_account_name,
1084 const gchar *mailbox,
1085 const gchar *msg_uid)
1087 return modest_msg_view_window_new_with_other_body (msg, NULL, modest_account_name, mailbox, msg_uid);
1091 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1094 ModestMsgViewWindow *window)
1096 check_dimming_rules_after_change (window);
1100 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1102 ModestMsgViewWindow *window)
1104 check_dimming_rules_after_change (window);
1106 /* The window could have dissapeared */
1109 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1111 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1112 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1116 /* On insertions we check if the folder still has the message we are
1117 * showing or do not. If do not, we do nothing. Which means we are still
1118 * not attached to any header folder and thus next/prev buttons are
1119 * still dimmed. Once the message that is shown by msg-view is found, the
1120 * new model of header-view will be attached and the references will be set.
1121 * On each further insertions dimming rules will be checked. However
1122 * this requires extra CPU time at least works.
1123 * (An message might be deleted from TnyFolder and thus will not be
1124 * inserted into the model again for example if it is removed by the
1125 * imap server and the header view is refreshed.)
1128 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1129 GtkTreePath *tree_path,
1130 GtkTreeIter *tree_iter,
1131 ModestMsgViewWindow *window)
1133 ModestMsgViewWindowPrivate *priv = NULL;
1134 TnyHeader *header = NULL;
1136 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1137 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1139 g_assert (model == priv->header_model);
1141 /* Check if the newly inserted message is the same we are actually
1142 * showing. IF not, we should remain detached from the header model
1143 * and thus prev and next toolbar buttons should remain dimmed. */
1144 gtk_tree_model_get (model, tree_iter,
1145 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1148 if (TNY_IS_HEADER (header)) {
1151 uid = modest_tny_folder_get_header_unique_id (header);
1152 if (!g_str_equal(priv->msg_uid, uid)) {
1153 check_dimming_rules_after_change (window);
1155 g_object_unref (G_OBJECT(header));
1159 g_object_unref(G_OBJECT(header));
1162 if (priv->row_reference) {
1163 gtk_tree_row_reference_free (priv->row_reference);
1166 /* Setup row_reference for the actual msg. */
1167 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1168 if (priv->row_reference == NULL) {
1169 g_warning("No reference for msg header item.");
1173 /* Now set up next_row_reference. */
1174 if (priv->next_row_reference) {
1175 gtk_tree_row_reference_free (priv->next_row_reference);
1178 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1179 select_next_valid_row (priv->header_model,
1180 &(priv->next_row_reference), FALSE, priv->is_outbox);
1182 /* Connect the remaining callbacks to become able to detect
1183 * changes in header-view. */
1184 priv->row_changed_handler =
1185 g_signal_connect (priv->header_model, "row-changed",
1186 G_CALLBACK (modest_msg_view_window_on_row_changed),
1188 priv->row_deleted_handler =
1189 g_signal_connect (priv->header_model, "row-deleted",
1190 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1192 priv->rows_reordered_handler =
1193 g_signal_connect (priv->header_model, "rows-reordered",
1194 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1197 check_dimming_rules_after_change (window);
1201 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1205 ModestMsgViewWindow *window)
1207 ModestMsgViewWindowPrivate *priv = NULL;
1208 gboolean already_changed = FALSE;
1210 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1212 /* If the current row was reordered select the proper next
1213 valid row. The same if the next row reference changes */
1214 if (priv->row_reference &&
1215 gtk_tree_row_reference_valid (priv->row_reference)) {
1217 path = gtk_tree_row_reference_get_path (priv->row_reference);
1218 if (gtk_tree_path_compare (path, arg1) == 0) {
1219 if (priv->next_row_reference) {
1220 gtk_tree_row_reference_free (priv->next_row_reference);
1222 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1223 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1224 already_changed = TRUE;
1226 gtk_tree_path_free (path);
1228 if (!already_changed &&
1229 priv->next_row_reference &&
1230 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1232 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1233 if (gtk_tree_path_compare (path, arg1) == 0) {
1234 if (priv->next_row_reference) {
1235 gtk_tree_row_reference_free (priv->next_row_reference);
1237 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1238 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1240 gtk_tree_path_free (path);
1242 check_dimming_rules_after_change (window);
1245 /* The modest_msg_view_window_update_model_replaced implements update
1246 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1247 * actually belongs to the header-view is the same as the TnyFolder of
1248 * the message of msg-view or not. If they are different, there is
1249 * nothing to do. If they are the same, then the model has replaced and
1250 * the reference in msg-view shall be replaced from the old model to
1251 * the new model. In this case the view will be detached from it's
1252 * header folder. From this point the next/prev buttons are dimmed.
1255 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1256 GtkTreeModel *model,
1257 const gchar *tny_folder_id)
1259 ModestMsgViewWindowPrivate *priv = NULL;
1260 ModestMsgViewWindow *window = NULL;
1262 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1263 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1265 window = MODEST_MSG_VIEW_WINDOW(observer);
1266 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1268 /* If there is an other folder in the header-view then we do
1269 * not care about it's model (msg list). Else if the
1270 * header-view shows the folder the msg shown by us is in, we
1271 * shall replace our model reference and make some check. */
1272 if(model == NULL || tny_folder_id == NULL ||
1273 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1276 /* Model is changed(replaced), so we should forget the old
1277 * one. Because there might be other references and there
1278 * might be some change on the model even if we unreferenced
1279 * it, we need to disconnect our signals here. */
1280 if (priv->header_model) {
1281 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1282 priv->row_changed_handler))
1283 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1284 priv->row_changed_handler);
1285 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1286 priv->row_deleted_handler))
1287 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1288 priv->row_deleted_handler);
1289 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1290 priv->row_inserted_handler))
1291 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1292 priv->row_inserted_handler);
1293 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1294 priv->rows_reordered_handler))
1295 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1296 priv->rows_reordered_handler);
1299 if (priv->row_reference)
1300 gtk_tree_row_reference_free (priv->row_reference);
1301 if (priv->next_row_reference)
1302 gtk_tree_row_reference_free (priv->next_row_reference);
1303 g_object_unref(priv->header_model);
1306 priv->row_changed_handler = 0;
1307 priv->row_deleted_handler = 0;
1308 priv->row_inserted_handler = 0;
1309 priv->rows_reordered_handler = 0;
1310 priv->next_row_reference = NULL;
1311 priv->row_reference = NULL;
1312 priv->header_model = NULL;
1315 priv->header_model = g_object_ref (model);
1317 /* Also we must connect to the new model for row insertions.
1318 * Only for insertions now. We will need other ones only after
1319 * the msg is show by msg-view is added to the new model. */
1320 priv->row_inserted_handler =
1321 g_signal_connect (priv->header_model, "row-inserted",
1322 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1325 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1326 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1330 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1332 ModestMsgViewWindowPrivate *priv= NULL;
1334 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1335 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1337 return priv->progress_hint;
1341 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1343 ModestMsgViewWindowPrivate *priv= NULL;
1345 TnyHeader *header = NULL;
1346 GtkTreePath *path = NULL;
1349 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1350 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1352 if (priv->is_other_body)
1355 /* If the message was not obtained from a treemodel,
1356 * for instance if it was opened directly by the search UI:
1358 if (priv->header_model == NULL ||
1359 priv->row_reference == NULL ||
1360 !gtk_tree_row_reference_valid (priv->row_reference)) {
1361 msg = modest_msg_view_window_get_message (self);
1363 header = tny_msg_get_header (msg);
1364 g_object_unref (msg);
1369 /* Get iter of the currently selected message in the header view: */
1370 path = gtk_tree_row_reference_get_path (priv->row_reference);
1371 g_return_val_if_fail (path != NULL, NULL);
1372 gtk_tree_model_get_iter (priv->header_model,
1376 /* Get current message header */
1377 gtk_tree_model_get (priv->header_model, &iter,
1378 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1381 gtk_tree_path_free (path);
1386 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1388 ModestMsgViewWindowPrivate *priv;
1390 g_return_val_if_fail (self, NULL);
1392 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1394 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1398 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1400 ModestMsgViewWindowPrivate *priv;
1402 g_return_val_if_fail (self, NULL);
1404 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1406 return (const gchar*) priv->msg_uid;
1410 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1413 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1414 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1415 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1419 is_active = gtk_toggle_action_get_active (toggle);
1422 gtk_widget_show (priv->find_toolbar);
1423 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1425 gtk_widget_hide (priv->find_toolbar);
1426 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1429 /* update the toggle buttons status */
1430 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1432 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1437 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1438 ModestMsgViewWindow *obj)
1440 GtkToggleAction *toggle;
1441 ModestWindowPrivate *parent_priv;
1442 ModestMsgViewWindowPrivate *priv;
1444 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1445 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1447 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1448 gtk_toggle_action_set_active (toggle, FALSE);
1449 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1453 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1454 ModestMsgViewWindow *obj)
1456 gchar *current_search;
1457 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1459 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1460 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1464 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1466 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1467 g_free (current_search);
1468 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
1472 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1474 g_free (priv->last_search);
1475 priv->last_search = g_strdup (current_search);
1476 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1479 hildon_banner_show_information (NULL, NULL,
1480 _HL("ckct_ib_find_no_matches"));
1481 g_free (priv->last_search);
1482 priv->last_search = NULL;
1484 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1487 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1488 hildon_banner_show_information (NULL, NULL,
1489 _HL("ckct_ib_find_search_complete"));
1490 g_free (priv->last_search);
1491 priv->last_search = NULL;
1493 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1497 g_free (current_search);
1502 modest_msg_view_window_set_zoom (ModestWindow *window,
1505 ModestMsgViewWindowPrivate *priv;
1506 ModestWindowPrivate *parent_priv;
1508 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1510 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1511 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1512 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1517 modest_msg_view_window_get_zoom (ModestWindow *window)
1519 ModestMsgViewWindowPrivate *priv;
1521 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1523 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1524 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1528 modest_msg_view_window_zoom_plus (ModestWindow *window)
1531 ModestMsgViewWindowPrivate *priv;
1535 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1536 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1538 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1540 if (zoom_level >= 2.0) {
1541 hildon_banner_show_information (NULL, NULL,
1542 _CS("ckct_ib_max_zoom_level_reached"));
1544 } else if (zoom_level >= 1.5) {
1546 } else if (zoom_level >= 1.2) {
1548 } else if (zoom_level >= 1.0) {
1550 } else if (zoom_level >= 0.8) {
1552 } else if (zoom_level >= 0.5) {
1558 /* set zoom level */
1559 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1560 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1561 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1562 g_free (banner_text);
1563 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1569 modest_msg_view_window_zoom_minus (ModestWindow *window)
1572 ModestMsgViewWindowPrivate *priv;
1576 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1577 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1579 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1581 if (zoom_level <= 0.5) {
1582 hildon_banner_show_information (NULL, NULL,
1583 _CS("ckct_ib_min_zoom_level_reached"));
1585 } else if (zoom_level <= 0.8) {
1587 } else if (zoom_level <= 1.0) {
1589 } else if (zoom_level <= 1.2) {
1591 } else if (zoom_level <= 1.5) {
1593 } else if (zoom_level <= 2.0) {
1599 /* set zoom level */
1600 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1601 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1602 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1603 g_free (banner_text);
1604 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1611 modest_msg_view_window_key_event (GtkWidget *window,
1617 focus = gtk_window_get_focus (GTK_WINDOW (window));
1619 /* for the find toolbar case */
1620 if (focus && GTK_IS_ENTRY (focus)) {
1621 if (event->keyval == GDK_BackSpace) {
1623 copy = gdk_event_copy ((GdkEvent *) event);
1624 gtk_widget_event (focus, copy);
1625 gdk_event_free (copy);
1630 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1631 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1632 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1633 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1634 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1635 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1636 /* ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); */
1637 /* gboolean return_value; */
1639 if (event->type == GDK_KEY_PRESS) {
1640 GtkScrollType scroll_type;
1642 switch (event->keyval) {
1645 scroll_type = GTK_SCROLL_STEP_UP; break;
1648 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1650 case GDK_KP_Page_Up:
1651 scroll_type = GTK_SCROLL_PAGE_UP; break;
1653 case GDK_KP_Page_Down:
1654 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1657 scroll_type = GTK_SCROLL_START; break;
1660 scroll_type = GTK_SCROLL_END; break;
1661 default: scroll_type = GTK_SCROLL_NONE;
1664 /* g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", */
1665 /* scroll_type, FALSE, &return_value); */
1676 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1679 ModestMsgViewWindowPrivate *priv;
1680 GtkTreeIter tmp_iter;
1681 gboolean is_last_selected;
1683 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1684 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1686 /*if no model (so no rows at all), then virtually we are the last*/
1687 if (!priv->header_model || !priv->row_reference)
1690 if (!gtk_tree_row_reference_valid (priv->row_reference))
1693 path = gtk_tree_row_reference_get_path (priv->row_reference);
1697 is_last_selected = TRUE;
1698 while (is_last_selected) {
1700 gtk_tree_path_next (path);
1701 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1703 gtk_tree_model_get (priv->header_model, &tmp_iter,
1704 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1707 if (msg_is_visible (header, priv->is_outbox))
1708 is_last_selected = FALSE;
1709 g_object_unref(G_OBJECT(header));
1712 gtk_tree_path_free (path);
1713 return is_last_selected;
1717 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1719 ModestMsgViewWindowPrivate *priv;
1721 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1722 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1724 return priv->header_model != NULL;
1728 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1730 ModestMsgViewWindowPrivate *priv;
1732 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1733 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1735 return priv->is_search_result;
1739 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1741 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1743 if (!check_outbox) {
1746 ModestTnySendQueueStatus status;
1747 status = modest_tny_all_send_queues_get_msg_status (header);
1748 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1749 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1754 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1757 ModestMsgViewWindowPrivate *priv;
1758 gboolean is_first_selected;
1759 GtkTreeIter tmp_iter;
1761 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1762 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1764 /*if no model (so no rows at all), then virtually we are the first*/
1765 if (!priv->header_model || !priv->row_reference)
1768 if (!gtk_tree_row_reference_valid (priv->row_reference))
1771 path = gtk_tree_row_reference_get_path (priv->row_reference);
1775 is_first_selected = TRUE;
1776 while (is_first_selected) {
1778 if(!gtk_tree_path_prev (path))
1780 /* Here the 'if' is needless for logic, but let make sure
1781 * iter is valid for gtk_tree_model_get. */
1782 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1784 gtk_tree_model_get (priv->header_model, &tmp_iter,
1785 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1788 if (msg_is_visible (header, priv->is_outbox))
1789 is_first_selected = FALSE;
1790 g_object_unref(G_OBJECT(header));
1793 gtk_tree_path_free (path);
1794 return is_first_selected;
1799 GtkTreeRowReference *row_reference;
1803 message_reader_performer (gboolean canceled,
1805 GtkWindow *parent_window,
1806 TnyAccount *account,
1809 ModestMailOperation *mail_op = NULL;
1810 MsgReaderInfo *info;
1812 info = (MsgReaderInfo *) user_data;
1813 if (canceled || err) {
1814 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1818 /* Register the header - it'll be unregistered in the callback */
1819 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1821 /* New mail operation */
1822 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1823 modest_ui_actions_disk_operations_error_handler,
1826 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1827 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1828 g_object_unref (mail_op);
1830 /* Update dimming rules */
1831 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1832 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1835 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1836 g_object_unref (info->header);
1837 g_slice_free (MsgReaderInfo, info);
1842 * Reads the message whose summary item is @header. It takes care of
1843 * several things, among others:
1845 * If the message was not previously downloaded then ask the user
1846 * before downloading. If there is no connection launch the connection
1847 * dialog. Update toolbar dimming rules.
1849 * Returns: TRUE if the mail operation was started, otherwise if the
1850 * user do not want to download the message, or if the user do not
1851 * want to connect, then the operation is not issued
1854 message_reader (ModestMsgViewWindow *window,
1855 ModestMsgViewWindowPrivate *priv,
1857 GtkTreeRowReference *row_reference)
1859 ModestWindowMgr *mgr;
1860 TnyAccount *account;
1862 MsgReaderInfo *info;
1864 g_return_val_if_fail (row_reference != NULL, FALSE);
1866 /* We set the header from model while we're loading */
1867 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
1868 gtk_window_set_title (GTK_WINDOW (window), _CS("ckdg_pb_updating"));
1870 mgr = modest_runtime_get_window_mgr ();
1871 /* Msg download completed */
1872 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1874 /* Ask the user if he wants to download the message if
1876 if (!tny_device_is_online (modest_runtime_get_device())) {
1877 GtkResponseType response;
1879 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1880 _("mcen_nc_get_msg"));
1881 if (response == GTK_RESPONSE_CANCEL) {
1882 update_window_title (window);
1886 folder = tny_header_get_folder (header);
1887 info = g_slice_new (MsgReaderInfo);
1888 info->header = g_object_ref (header);
1889 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1891 /* Offer the connection dialog if necessary */
1892 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
1894 TNY_FOLDER_STORE (folder),
1895 message_reader_performer,
1897 g_object_unref (folder);
1902 folder = tny_header_get_folder (header);
1903 account = tny_folder_get_account (folder);
1904 info = g_slice_new (MsgReaderInfo);
1905 info->header = g_object_ref (header);
1906 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1908 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
1909 g_object_unref (account);
1910 g_object_unref (folder);
1916 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1918 ModestMsgViewWindowPrivate *priv;
1919 GtkTreePath *path= NULL;
1920 GtkTreeIter tmp_iter;
1922 gboolean retval = TRUE;
1923 GtkTreeRowReference *row_reference = NULL;
1925 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1926 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1928 if (!priv->row_reference)
1931 /* Update the next row reference if it's not valid. This could
1932 happen if for example the header which it was pointing to,
1933 was deleted. The best place to do it is in the row-deleted
1934 handler but the tinymail model do not work like the glib
1935 tree models and reports the deletion when the row is still
1937 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1938 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1939 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1940 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1943 if (priv->next_row_reference)
1944 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1948 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1950 gtk_tree_model_get_iter (priv->header_model,
1953 gtk_tree_path_free (path);
1955 gtk_tree_model_get (priv->header_model, &tmp_iter,
1956 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1959 /* Read the message & show it */
1960 if (!message_reader (window, priv, header, row_reference)) {
1963 gtk_tree_row_reference_free (row_reference);
1966 g_object_unref (header);
1972 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1974 ModestMsgViewWindowPrivate *priv = NULL;
1976 gboolean finished = FALSE;
1977 gboolean retval = FALSE;
1979 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1980 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1982 /* Return inmediatly if there is no header model */
1983 if (!priv->header_model || !priv->row_reference)
1986 path = gtk_tree_row_reference_get_path (priv->row_reference);
1987 while (!finished && gtk_tree_path_prev (path)) {
1991 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1992 gtk_tree_model_get (priv->header_model, &iter,
1993 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1997 if (msg_is_visible (header, priv->is_outbox)) {
1998 GtkTreeRowReference *row_reference;
1999 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2000 /* Read the message & show it */
2001 retval = message_reader (window, priv, header, row_reference);
2002 gtk_tree_row_reference_free (row_reference);
2006 g_object_unref (header);
2010 gtk_tree_path_free (path);
2015 view_msg_cb (ModestMailOperation *mail_op,
2022 ModestMsgViewWindow *self = NULL;
2023 ModestMsgViewWindowPrivate *priv = NULL;
2024 GtkTreeRowReference *row_reference = NULL;
2026 /* Unregister the header (it was registered before creating the mail operation) */
2027 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2029 row_reference = (GtkTreeRowReference *) user_data;
2031 gtk_tree_row_reference_free (row_reference);
2032 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2034 /* Restore window title */
2035 update_window_title (self);
2036 g_object_unref (self);
2041 /* If there was any error */
2042 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2043 gtk_tree_row_reference_free (row_reference);
2044 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2046 /* Restore window title */
2047 update_window_title (self);
2048 g_object_unref (self);
2053 /* Get the window */
2054 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2055 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2056 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2058 /* Update the row reference */
2059 if (priv->row_reference != NULL) {
2060 gtk_tree_row_reference_free (priv->row_reference);
2061 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
2062 if (priv->next_row_reference != NULL) {
2063 gtk_tree_row_reference_free (priv->next_row_reference);
2065 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2066 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2069 /* Mark header as read */
2070 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2071 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2073 /* Set new message */
2074 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2075 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2076 modest_msg_view_window_update_priority (self);
2077 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2078 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2081 /* Set the new message uid of the window */
2082 if (priv->msg_uid) {
2083 g_free (priv->msg_uid);
2084 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2087 /* Notify the observers */
2088 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2089 0, priv->header_model, priv->row_reference);
2092 g_object_unref (self);
2093 gtk_tree_row_reference_free (row_reference);
2097 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2099 ModestMsgViewWindowPrivate *priv;
2101 TnyFolderType folder_type;
2103 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2105 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2107 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2111 folder = tny_msg_get_folder (msg);
2113 folder_type = modest_tny_folder_guess_folder_type (folder);
2114 g_object_unref (folder);
2116 g_object_unref (msg);
2124 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2126 ModestMsgViewWindowPrivate *priv;
2127 TnyHeader *header = NULL;
2128 TnyHeaderFlags flags = 0;
2130 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2132 if (priv->header_model && priv->row_reference) {
2134 GtkTreePath *path = NULL;
2136 path = gtk_tree_row_reference_get_path (priv->row_reference);
2137 g_return_if_fail (path != NULL);
2138 gtk_tree_model_get_iter (priv->header_model,
2140 gtk_tree_row_reference_get_path (priv->row_reference));
2142 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2144 gtk_tree_path_free (path);
2147 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2149 header = tny_msg_get_header (msg);
2150 g_object_unref (msg);
2155 flags = tny_header_get_flags (header);
2156 g_object_unref(G_OBJECT(header));
2159 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2164 toolbar_resize (ModestMsgViewWindow *self)
2166 ModestMsgViewWindowPrivate *priv = NULL;
2167 ModestWindowPrivate *parent_priv = NULL;
2169 gint static_button_size;
2170 ModestWindowMgr *mgr;
2172 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2173 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2174 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2176 mgr = modest_runtime_get_window_mgr ();
2177 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2179 if (parent_priv->toolbar) {
2180 /* left size buttons */
2181 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2182 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2183 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2184 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2185 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
2186 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2187 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2188 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2189 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2190 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2191 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2192 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2193 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
2194 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2195 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2196 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2198 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2199 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2200 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2201 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2206 modest_msg_view_window_show_toolbar (ModestWindow *self,
2207 gboolean show_toolbar)
2209 ModestMsgViewWindowPrivate *priv = NULL;
2210 ModestWindowPrivate *parent_priv;
2212 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2213 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2215 /* Set optimized view status */
2216 priv->optimized_view = !show_toolbar;
2218 if (!parent_priv->toolbar) {
2219 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2221 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2222 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2224 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2225 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2226 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2229 hildon_window_add_toolbar (HILDON_WINDOW (self),
2230 GTK_TOOLBAR (parent_priv->toolbar));
2235 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2236 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2237 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2239 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2240 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2241 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2243 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2246 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2247 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2252 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2254 ModestMsgViewWindow *window)
2256 if (!GTK_WIDGET_VISIBLE (window))
2259 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2263 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2265 ModestMsgViewWindowPrivate *priv;
2267 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2268 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2270 return priv->progress_hint;
2274 observers_empty (ModestMsgViewWindow *self)
2277 ModestMsgViewWindowPrivate *priv;
2278 gboolean is_empty = TRUE;
2279 guint pending_ops = 0;
2281 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2282 tmp = priv->progress_widgets;
2284 /* Check all observers */
2285 while (tmp && is_empty) {
2286 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2287 is_empty = pending_ops == 0;
2289 tmp = g_slist_next(tmp);
2296 on_account_removed (TnyAccountStore *account_store,
2297 TnyAccount *account,
2300 /* Do nothing if it's a transport account, because we only
2301 show the messages of a store account */
2302 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2303 const gchar *parent_acc = NULL;
2304 const gchar *our_acc = NULL;
2306 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2307 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2309 /* Close this window if I'm showing a message of the removed account */
2310 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2311 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2316 on_mail_operation_started (ModestMailOperation *mail_op,
2319 ModestMsgViewWindow *self;
2320 ModestMailOperationTypeOperation op_type;
2322 ModestMsgViewWindowPrivate *priv;
2323 GObject *source = NULL;
2325 self = MODEST_MSG_VIEW_WINDOW (user_data);
2326 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2327 op_type = modest_mail_operation_get_type_operation (mail_op);
2328 tmp = priv->progress_widgets;
2329 source = modest_mail_operation_get_source(mail_op);
2330 if (G_OBJECT (self) == source) {
2331 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2332 set_toolbar_transfer_mode(self);
2334 modest_progress_object_add_operation (
2335 MODEST_PROGRESS_OBJECT (tmp->data),
2337 tmp = g_slist_next (tmp);
2341 g_object_unref (source);
2345 on_mail_operation_finished (ModestMailOperation *mail_op,
2348 ModestMsgViewWindow *self;
2349 ModestMailOperationTypeOperation op_type;
2351 ModestMsgViewWindowPrivate *priv;
2353 self = MODEST_MSG_VIEW_WINDOW (user_data);
2354 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2355 op_type = modest_mail_operation_get_type_operation (mail_op);
2356 tmp = priv->progress_widgets;
2358 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2360 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2362 tmp = g_slist_next (tmp);
2365 /* If no more operations are being observed, NORMAL mode is enabled again */
2366 if (observers_empty (self)) {
2367 set_progress_hint (self, FALSE);
2371 /* Update dimming rules. We have to do this right here
2372 and not in view_msg_cb because at that point the
2373 transfer mode is still enabled so the dimming rule
2374 won't let the user delete the message that has been
2375 readed for example */
2376 check_dimming_rules_after_change (self);
2381 on_queue_changed (ModestMailOperationQueue *queue,
2382 ModestMailOperation *mail_op,
2383 ModestMailOperationQueueNotification type,
2384 ModestMsgViewWindow *self)
2386 ModestMsgViewWindowPrivate *priv;
2388 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2390 /* If this operations was created by another window, do nothing */
2391 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2394 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2395 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2397 "operation-started",
2398 G_CALLBACK (on_mail_operation_started),
2400 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2402 "operation-finished",
2403 G_CALLBACK (on_mail_operation_finished),
2405 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2406 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2408 "operation-started");
2409 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2411 "operation-finished");
2416 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2418 ModestMsgViewWindowPrivate *priv;
2419 TnyList *selected_attachments = NULL;
2421 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2422 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2424 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2425 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2427 return selected_attachments;
2431 ModestMsgViewWindow *self;
2433 } DecodeAsyncHelper;
2436 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2442 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2444 /* It could happen that the window was closed */
2445 if (GTK_WIDGET_VISIBLE (helper->self))
2446 set_progress_hint (helper->self, FALSE);
2448 if (cancelled || err) {
2450 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2451 modest_platform_information_banner (NULL, NULL, msg);
2457 /* make the file read-only */
2458 g_chmod(helper->file_path, 0444);
2460 /* Activate the file */
2461 modest_platform_activate_file (helper->file_path, tny_mime_part_get_content_type (mime_part));
2465 g_object_unref (helper->self);
2466 g_free (helper->file_path);
2467 g_slice_free (DecodeAsyncHelper, helper);
2471 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2472 TnyMimePart *mime_part)
2474 ModestMsgViewWindowPrivate *priv;
2475 const gchar *msg_uid;
2476 gchar *attachment_uid = NULL;
2477 gint attachment_index = 0;
2478 TnyList *attachments;
2480 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2481 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2482 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2484 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2485 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2486 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2487 g_object_unref (attachments);
2489 if (msg_uid && attachment_index >= 0) {
2490 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2493 if (mime_part == NULL) {
2494 gboolean error = FALSE;
2495 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2496 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2498 } else if (tny_list_get_length (selected_attachments) > 1) {
2499 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2503 iter = tny_list_create_iterator (selected_attachments);
2504 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2505 g_object_unref (iter);
2507 if (selected_attachments)
2508 g_object_unref (selected_attachments);
2513 g_object_ref (mime_part);
2516 if (tny_mime_part_is_purged (mime_part))
2519 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2520 gchar *filepath = NULL;
2521 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2522 gboolean show_error_banner = FALSE;
2523 TnyFsStream *temp_stream = NULL;
2524 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2527 if (temp_stream != NULL) {
2528 DecodeAsyncHelper *helper;
2530 /* Activate progress hint */
2531 set_progress_hint (window, TRUE);
2533 helper = g_slice_new0 (DecodeAsyncHelper);
2534 helper->self = g_object_ref (window);
2535 helper->file_path = g_strdup (filepath);
2537 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2538 on_decode_to_stream_async_handler,
2541 g_object_unref (temp_stream);
2542 /* NOTE: files in the temporary area will be automatically
2543 * cleaned after some time if they are no longer in use */
2546 const gchar *content_type;
2547 /* the file may already exist but it isn't writable,
2548 * let's try to open it anyway */
2549 content_type = tny_mime_part_get_content_type (mime_part);
2550 modest_platform_activate_file (filepath, content_type);
2552 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2553 show_error_banner = TRUE;
2558 if (show_error_banner)
2559 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2560 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2561 ModestWindowMgr *mgr;
2562 mgr = modest_runtime_get_window_mgr ();
2563 ModestWindow *msg_win = NULL;
2564 TnyMsg *current_msg;
2566 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2567 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2569 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2571 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2572 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part),
2573 account, mailbox, attachment_uid);
2574 g_object_unref (current_msg);
2576 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2577 modest_window_get_zoom (MODEST_WINDOW (window)));
2578 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2579 gtk_widget_show_all (GTK_WIDGET (msg_win));
2581 gtk_widget_destroy (GTK_WIDGET (msg_win));
2584 /* message attachment */
2585 TnyHeader *header = NULL;
2586 ModestWindowMgr *mgr;
2587 ModestWindow *msg_win = NULL;
2590 header = tny_msg_get_header (TNY_MSG (mime_part));
2591 mgr = modest_runtime_get_window_mgr ();
2592 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2595 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2596 * thus, we don't do anything */
2597 g_warning ("window for is already being created");
2599 /* it's not found, so create a new window for it */
2600 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2601 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2602 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2604 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2605 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account,
2606 mailbox, attachment_uid);
2607 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2608 modest_window_get_zoom (MODEST_WINDOW (window)));
2609 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2610 gtk_widget_show_all (GTK_WIDGET (msg_win));
2612 gtk_widget_destroy (GTK_WIDGET (msg_win));
2618 g_free (attachment_uid);
2620 g_object_unref (mime_part);
2632 GnomeVFSResult result;
2635 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2636 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2637 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2638 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2641 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2645 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2646 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2647 g_free (pair->filename);
2648 g_object_unref (pair->part);
2649 g_slice_free (SaveMimePartPair, pair);
2651 g_list_free (info->pairs);
2654 g_slice_free (SaveMimePartInfo, info);
2659 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2661 if (info->pairs != NULL) {
2662 save_mime_part_to_file (info);
2664 /* This is a GDK lock because we are an idle callback and
2665 * hildon_banner_show_information is or does Gtk+ code */
2667 gdk_threads_enter (); /* CHECKED */
2668 save_mime_part_info_free (info, TRUE);
2669 if (info->result == GNOME_VFS_OK) {
2670 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2671 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
2672 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2673 modest_platform_information_banner (NULL, NULL, msg);
2676 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2678 gdk_threads_leave (); /* CHECKED */
2685 save_mime_part_to_file (SaveMimePartInfo *info)
2687 GnomeVFSHandle *handle;
2689 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2691 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2692 if (info->result == GNOME_VFS_OK) {
2693 GError *error = NULL;
2694 stream = tny_vfs_stream_new (handle);
2695 if (tny_mime_part_decode_to_stream (pair->part, stream, &error) < 0) {
2696 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
2698 if ((error->domain == TNY_ERROR_DOMAIN) &&
2699 (error->code == TNY_IO_ERROR_WRITE) &&
2700 (errno == ENOSPC)) {
2701 info->result = GNOME_VFS_ERROR_NO_SPACE;
2703 info->result = GNOME_VFS_ERROR_IO;
2706 g_object_unref (G_OBJECT (stream));
2707 g_object_unref (pair->part);
2708 g_slice_free (SaveMimePartPair, pair);
2709 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2711 g_warning ("modest: could not create save attachment %s: %s\n", pair->filename, gnome_vfs_result_to_string (info->result));
2712 save_mime_part_info_free (info, FALSE);
2715 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2720 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2722 gboolean is_ok = TRUE;
2723 gint replaced_files = 0;
2724 const GList *files = info->pairs;
2727 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2728 SaveMimePartPair *pair = iter->data;
2729 if (modest_utils_file_exists (pair->filename)) {
2733 if (replaced_files) {
2734 GtkWidget *confirm_overwrite_dialog;
2736 if (replaced_files == 1) {
2737 SaveMimePartPair *pair = files->data;
2738 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
2740 gchar *message = g_strdup_printf ("%s\n%s",
2741 _FM("docm_nc_replace_file"),
2742 (basename) ? basename : "");
2743 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2746 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL,
2747 _FM("docm_nc_replace_multiple"));
2749 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK)
2752 gtk_widget_destroy (confirm_overwrite_dialog);
2756 save_mime_part_info_free (info, TRUE);
2758 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2764 save_attachments_response (GtkDialog *dialog,
2768 TnyList *mime_parts;
2770 GList *files_to_save = NULL;
2771 gchar *current_folder;
2773 mime_parts = TNY_LIST (user_data);
2775 if (arg1 != GTK_RESPONSE_OK)
2778 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
2779 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2780 if (current_folder && current_folder != '\0') {
2782 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
2783 current_folder,&err);
2785 g_debug ("Error storing latest used folder: %s", err->message);
2789 g_free (current_folder);
2791 if (!modest_utils_folder_writable (chooser_uri)) {
2792 hildon_banner_show_information
2793 (NULL, NULL, _FM("sfil_ib_readonly_location"));
2797 iter = tny_list_create_iterator (mime_parts);
2798 while (!tny_iterator_is_done (iter)) {
2799 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2801 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
2802 !tny_mime_part_is_purged (mime_part) &&
2803 (tny_mime_part_get_filename (mime_part) != NULL)) {
2804 SaveMimePartPair *pair;
2806 pair = g_slice_new0 (SaveMimePartPair);
2808 if (tny_list_get_length (mime_parts) > 1) {
2810 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
2811 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
2814 pair->filename = g_strdup (chooser_uri);
2816 pair->part = mime_part;
2817 files_to_save = g_list_prepend (files_to_save, pair);
2819 tny_iterator_next (iter);
2821 g_object_unref (iter);
2823 g_free (chooser_uri);
2825 if (files_to_save != NULL) {
2826 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2827 info->pairs = files_to_save;
2828 info->result = TRUE;
2829 save_mime_parts_to_file_with_checks (info);
2833 /* Free and close the dialog */
2834 g_object_unref (mime_parts);
2835 gtk_widget_destroy (GTK_WIDGET (dialog));
2839 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
2840 TnyList *mime_parts)
2842 ModestMsgViewWindowPrivate *priv;
2843 GtkWidget *save_dialog = NULL;
2844 gchar *conf_folder = NULL;
2845 gchar *filename = NULL;
2846 gchar *save_multiple_str = NULL;
2848 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2849 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2851 if (mime_parts == NULL) {
2852 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
2853 * selection available */
2854 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2855 if (mime_parts && !modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, FALSE)) {
2856 g_object_unref (mime_parts);
2859 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
2861 g_object_unref (mime_parts);
2867 g_object_ref (mime_parts);
2870 /* prepare dialog */
2871 if (tny_list_get_length (mime_parts) == 1) {
2873 /* only one attachment selected */
2874 iter = tny_list_create_iterator (mime_parts);
2875 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2876 g_object_unref (iter);
2877 if (!modest_tny_mime_part_is_msg (mime_part) &&
2878 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
2879 !tny_mime_part_is_purged (mime_part)) {
2880 filename = g_strdup (tny_mime_part_get_filename (mime_part));
2882 /* TODO: show any error? */
2883 g_warning ("Tried to save a non-file attachment");
2884 g_object_unref (mime_parts);
2887 g_object_unref (mime_part);
2889 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2890 tny_list_get_length (mime_parts));
2893 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2894 GTK_FILE_CHOOSER_ACTION_SAVE);
2897 conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
2898 if (conf_folder && conf_folder[0] != '\0') {
2899 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
2902 /* Set the default folder to images folder */
2903 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
2904 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
2905 g_free (docs_folder);
2907 g_free (conf_folder);
2911 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2916 /* if multiple, set multiple string */
2917 if (save_multiple_str) {
2918 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2919 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
2922 /* We must run this asynchronously, because the hildon dialog
2923 performs a gtk_dialog_run by itself which leads to gdk
2925 g_signal_connect (save_dialog, "response",
2926 G_CALLBACK (save_attachments_response), mime_parts);
2928 gtk_widget_show_all (save_dialog);
2932 show_remove_attachment_information (gpointer userdata)
2934 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2935 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2937 /* We're outside the main lock */
2938 gdk_threads_enter ();
2940 if (priv->remove_attachment_banner != NULL) {
2941 gtk_widget_destroy (priv->remove_attachment_banner);
2942 g_object_unref (priv->remove_attachment_banner);
2945 priv->remove_attachment_banner = g_object_ref (
2946 hildon_banner_show_animation (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
2948 gdk_threads_leave ();
2954 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2956 ModestMsgViewWindowPrivate *priv;
2957 TnyList *mime_parts = NULL, *tmp;
2958 gchar *confirmation_message;
2964 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2965 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2967 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
2968 * because we don't have selection
2970 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2972 /* Remove already purged messages from mime parts list. We use
2973 a copy of the list to remove items in the original one */
2974 tmp = tny_list_copy (mime_parts);
2975 iter = tny_list_create_iterator (tmp);
2976 while (!tny_iterator_is_done (iter)) {
2977 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
2978 if (tny_mime_part_is_purged (part))
2979 tny_list_remove (mime_parts, (GObject *) part);
2981 g_object_unref (part);
2982 tny_iterator_next (iter);
2984 g_object_unref (tmp);
2985 g_object_unref (iter);
2987 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
2988 tny_list_get_length (mime_parts) == 0) {
2989 g_object_unref (mime_parts);
2993 n_attachments = tny_list_get_length (mime_parts);
2994 if (n_attachments == 1) {
2998 iter = tny_list_create_iterator (mime_parts);
2999 part = (TnyMimePart *) tny_iterator_get_current (iter);
3000 g_object_unref (iter);
3001 if (modest_tny_mime_part_is_msg (part)) {
3003 header = tny_msg_get_header (TNY_MSG (part));
3004 filename = tny_header_dup_subject (header);
3005 g_object_unref (header);
3006 if (filename == NULL)
3007 filename = g_strdup (_("mail_va_no_subject"));
3009 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3011 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3013 g_object_unref (part);
3015 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3016 "mcen_nc_purge_files_text",
3017 n_attachments), n_attachments);
3019 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3020 confirmation_message);
3021 g_free (confirmation_message);
3023 if (response != GTK_RESPONSE_OK) {
3024 g_object_unref (mime_parts);
3028 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3030 iter = tny_list_create_iterator (mime_parts);
3031 while (!tny_iterator_is_done (iter)) {
3034 part = (TnyMimePart *) tny_iterator_get_current (iter);
3035 tny_mime_part_set_purged (TNY_MIME_PART (part));
3036 g_object_unref (part);
3037 tny_iterator_next (iter);
3039 g_object_unref (iter);
3041 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3042 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3043 tny_msg_rewrite_cache (msg);
3044 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3045 g_object_unref (msg);
3047 g_object_unref (mime_parts);
3049 if (priv->purge_timeout > 0) {
3050 g_source_remove (priv->purge_timeout);
3051 priv->purge_timeout = 0;
3054 if (priv->remove_attachment_banner) {
3055 gtk_widget_destroy (priv->remove_attachment_banner);
3056 g_object_unref (priv->remove_attachment_banner);
3057 priv->remove_attachment_banner = NULL;
3063 update_window_title (ModestMsgViewWindow *window)
3065 ModestMsgViewWindowPrivate *priv;
3067 TnyHeader *header = NULL;
3068 gchar *subject = NULL;
3070 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3072 /* Note that if the window is closed while we're retrieving
3073 the message, this widget could de deleted */
3074 if (!priv->msg_view)
3077 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3080 header = tny_msg_get_header (msg);
3081 subject = tny_header_dup_subject (header);
3082 g_object_unref (header);
3083 g_object_unref (msg);
3086 if ((subject == NULL)||(subject[0] == '\0')) {
3088 subject = g_strdup (_("mail_va_no_subject"));
3091 gtk_window_set_title (GTK_WINDOW (window), subject);
3096 on_move_focus (GtkWidget *widget,
3097 GtkDirectionType direction,
3100 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3104 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3106 GnomeVFSResult result;
3107 GnomeVFSHandle *handle = NULL;
3108 GnomeVFSFileInfo *info = NULL;
3111 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3112 if (result != GNOME_VFS_OK) {
3117 info = gnome_vfs_file_info_new ();
3118 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3119 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3120 /* We put a "safe" default size for going to cache */
3121 *expected_size = (300*1024);
3123 *expected_size = info->size;
3125 gnome_vfs_file_info_unref (info);
3127 stream = tny_vfs_stream_new (handle);
3136 TnyStream *output_stream;
3137 GtkWidget *msg_view;
3142 on_fetch_image_idle_refresh_view (gpointer userdata)
3145 FetchImageData *fidata = (FetchImageData *) userdata;
3147 gdk_threads_enter ();
3148 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3149 ModestMsgViewWindowPrivate *priv;
3151 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3152 priv->fetching_images--;
3153 gtk_widget_queue_draw (fidata->msg_view);
3154 update_progress_hint (MODEST_MSG_VIEW_WINDOW (fidata->window));
3156 gdk_threads_leave ();
3158 g_object_unref (fidata->msg_view);
3159 g_object_unref (fidata->window);
3160 g_slice_free (FetchImageData, fidata);
3165 on_fetch_image_thread (gpointer userdata)
3167 FetchImageData *fidata = (FetchImageData *) userdata;
3168 TnyStreamCache *cache;
3169 TnyStream *cache_stream;
3171 cache = modest_runtime_get_images_cache ();
3173 tny_stream_cache_get_stream (cache,
3175 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3176 (gpointer) fidata->uri);
3177 g_free (fidata->cache_id);
3178 g_free (fidata->uri);
3180 if (cache_stream != NULL) {
3183 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3186 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3187 if (G_UNLIKELY (nb_read < 0)) {
3189 } else if (G_LIKELY (nb_read > 0)) {
3190 gssize nb_written = 0;
3192 while (G_UNLIKELY (nb_written < nb_read)) {
3195 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3196 nb_read - nb_written);
3197 if (G_UNLIKELY (len < 0))
3203 tny_stream_close (cache_stream);
3204 g_object_unref (cache_stream);
3207 tny_stream_close (fidata->output_stream);
3208 g_object_unref (fidata->output_stream);
3210 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3216 on_fetch_image (ModestMsgView *msgview,
3219 ModestMsgViewWindow *window)
3221 const gchar *current_account;
3222 ModestMsgViewWindowPrivate *priv;
3223 FetchImageData *fidata;
3225 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3227 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3229 fidata = g_slice_new0 (FetchImageData);
3230 fidata->msg_view = g_object_ref (msgview);
3231 fidata->window = g_object_ref (window);
3232 fidata->uri = g_strdup (uri);
3233 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3234 fidata->output_stream = g_object_ref (stream);
3236 priv->fetching_images++;
3237 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3238 g_object_unref (fidata->output_stream);
3239 g_free (fidata->cache_id);
3240 g_free (fidata->uri);
3241 g_object_unref (fidata->msg_view);
3242 g_slice_free (FetchImageData, fidata);
3243 tny_stream_close (stream);
3244 priv->fetching_images--;
3245 update_progress_hint (window);
3248 update_progress_hint (window);
3254 setup_menu (ModestMsgViewWindow *self)
3256 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3258 /* Settings menu buttons */
3259 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_replytoall"), NULL,
3260 APP_MENU_CALLBACK (modest_ui_actions_on_reply_all),
3261 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3262 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_forward"), "<Control>d",
3263 APP_MENU_CALLBACK (modest_ui_actions_on_forward),
3264 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3266 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3267 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3268 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3269 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3270 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3271 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3273 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3274 APP_MENU_CALLBACK (modest_ui_actions_save_attachments),
3275 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3276 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3277 APP_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3278 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3280 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3281 APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3282 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3283 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3284 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3285 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3287 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mail_bd_external_images"), NULL,
3288 APP_MENU_CALLBACK (modest_ui_actions_on_fetch_images),
3289 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_fetch_images));
3290 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3291 APP_MENU_CALLBACK (modest_ui_actions_on_details),
3292 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3296 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3298 ModestMsgViewWindowPrivate *priv;
3299 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3300 GSList *recipients = NULL;
3302 gboolean contacts_to_add = FALSE;
3304 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3308 header = modest_msg_view_window_get_header (self);
3311 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3312 g_object_unref (header);
3314 recipients = modest_tny_msg_get_all_recipients_list (msg);
3315 g_object_unref (msg);
3318 if (recipients != NULL) {
3319 GtkWidget *picker_dialog;
3320 GtkWidget *selector;
3322 gchar *selected = NULL;
3324 selector = hildon_touch_selector_new_text ();
3325 g_object_ref (selector);
3327 for (node = recipients; node != NULL; node = g_slist_next (node)) {
3328 if (!modest_address_book_has_address ((const gchar *) node->data)) {
3329 hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector),
3330 (const gchar *) node->data);
3331 contacts_to_add = TRUE;
3335 if (contacts_to_add) {
3338 picker_dialog = hildon_picker_dialog_new (GTK_WINDOW (self));
3339 gtk_window_set_title (GTK_WINDOW (picker_dialog), _("mcen_me_viewer_addtocontacts"));
3341 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (picker_dialog),
3342 HILDON_TOUCH_SELECTOR (selector));
3344 picker_result = gtk_dialog_run (GTK_DIALOG (picker_dialog));
3346 if (picker_result == GTK_RESPONSE_OK) {
3347 selected = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
3349 gtk_widget_destroy (picker_dialog);
3352 modest_address_book_add_address (selected);
3357 g_object_unref (selector);
3362 if (recipients) {g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);}
3366 _modest_msg_view_window_map_event (GtkWidget *widget,
3370 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
3372 update_progress_hint (self);
3378 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
3380 ModestMsgViewWindowPrivate *priv;
3381 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3383 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
3387 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
3389 ModestMsgViewWindowPrivate *priv;
3390 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3392 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
3394 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
3398 modest_msg_view_window_reload (ModestMsgViewWindow *self)
3400 ModestMsgViewWindowPrivate *priv;
3403 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
3405 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3406 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
3408 if (!message_reader (self, priv, header, priv->row_reference)) {
3409 g_warning ("Shouldn't happen, trying to reload a message failed");
3412 g_object_unref (header);