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>
69 #include <modest-account-protocol.h>
71 #define MYDOCS_ENV "MYDOCSDIR"
72 #define DOCS_FOLDER ".documents"
74 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
75 struct _ModestMsgViewWindowPrivate {
78 GtkWidget *main_scroll;
79 GtkWidget *find_toolbar;
82 /* Progress observers */
83 GSList *progress_widgets;
86 GtkWidget *prev_toolitem;
87 GtkWidget *next_toolitem;
88 gboolean progress_hint;
91 /* Optimized view enabled */
92 gboolean optimized_view;
94 /* Whether this was created via the *_new_for_search_result() function. */
95 gboolean is_search_result;
97 /* Whether the message is in outbox */
100 /* A reference to the @model of the header view
101 * to allow selecting previous/next messages,
102 * if the message is currently selected in the header view.
104 const gchar *header_folder_id;
105 GtkTreeModel *header_model;
106 GtkTreeRowReference *row_reference;
107 GtkTreeRowReference *next_row_reference;
109 gulong clipboard_change_handler;
110 gulong queue_change_handler;
111 gulong account_removed_handler;
112 gulong row_changed_handler;
113 gulong row_deleted_handler;
114 gulong row_inserted_handler;
115 gulong rows_reordered_handler;
118 GtkWidget *remove_attachment_banner;
121 TnyMimePart *other_body;
126 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
127 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
128 static void modest_header_view_observer_init(
129 ModestHeaderViewObserverIface *iface_class);
130 static void modest_msg_view_window_finalize (GObject *obj);
131 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
133 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
134 ModestMsgViewWindow *obj);
135 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
136 ModestMsgViewWindow *obj);
138 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
140 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
141 static void modest_msg_view_window_set_zoom (ModestWindow *window,
143 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
144 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
145 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
148 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
150 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
151 gboolean show_toolbar);
153 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
155 ModestMsgViewWindow *window);
157 static void modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
160 ModestMsgViewWindow *window);
162 static void modest_msg_view_window_on_row_deleted (GtkTreeModel *header_model,
164 ModestMsgViewWindow *window);
166 static void modest_msg_view_window_on_row_inserted (GtkTreeModel *header_model,
167 GtkTreePath *tree_path,
168 GtkTreeIter *tree_iter,
169 ModestMsgViewWindow *window);
171 static void modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
175 ModestMsgViewWindow *window);
177 static void modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *window,
179 const gchar *tny_folder_id);
181 static void on_queue_changed (ModestMailOperationQueue *queue,
182 ModestMailOperation *mail_op,
183 ModestMailOperationQueueNotification type,
184 ModestMsgViewWindow *self);
186 static void on_account_removed (TnyAccountStore *account_store,
190 static void on_move_focus (GtkWidget *widget,
191 GtkDirectionType direction,
194 static void view_msg_cb (ModestMailOperation *mail_op,
201 static void set_progress_hint (ModestMsgViewWindow *self,
204 static void update_window_title (ModestMsgViewWindow *window);
206 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
207 static void init_window (ModestMsgViewWindow *obj);
209 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
211 static void check_dimming_rules_after_change (ModestMsgViewWindow *window);
213 static gboolean on_fetch_image (ModestMsgView *msgview,
216 ModestMsgViewWindow *window);
218 static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
219 GtkScrollType scroll_type,
222 static gboolean message_reader (ModestMsgViewWindow *window,
223 ModestMsgViewWindowPrivate *priv,
225 const gchar *msg_uid,
227 GtkTreeRowReference *row_reference);
229 static void setup_menu (ModestMsgViewWindow *self);
230 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
233 static void update_branding (ModestMsgViewWindow *self);
236 /* list my signals */
243 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
244 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
247 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
248 MODEST_TYPE_MSG_VIEW_WINDOW, \
249 ModestMsgViewWindowPrivate))
251 static GtkWindowClass *parent_class = NULL;
253 /* uncomment the following if you have defined any signals */
254 static guint signals[LAST_SIGNAL] = {0};
257 modest_msg_view_window_get_type (void)
259 static GType my_type = 0;
261 static const GTypeInfo my_info = {
262 sizeof(ModestMsgViewWindowClass),
263 NULL, /* base init */
264 NULL, /* base finalize */
265 (GClassInitFunc) modest_msg_view_window_class_init,
266 NULL, /* class finalize */
267 NULL, /* class data */
268 sizeof(ModestMsgViewWindow),
270 (GInstanceInitFunc) modest_msg_view_window_init,
273 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
274 "ModestMsgViewWindow",
277 static const GInterfaceInfo modest_header_view_observer_info =
279 (GInterfaceInitFunc) modest_header_view_observer_init,
280 NULL, /* interface_finalize */
281 NULL /* interface_data */
284 g_type_add_interface_static (my_type,
285 MODEST_TYPE_HEADER_VIEW_OBSERVER,
286 &modest_header_view_observer_info);
292 save_state (ModestWindow *self)
294 modest_widget_memory_save (modest_runtime_get_conf (),
296 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
300 gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
301 GtkScrollType scroll_type,
305 ModestMsgViewWindowPrivate *priv;
306 gboolean return_value;
308 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
309 g_signal_emit_by_name (priv->main_scroll, "scroll-child", scroll_type, horizontal, &return_value);
314 add_scroll_binding (GtkBindingSet *binding_set,
316 GtkScrollType scroll)
318 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
320 gtk_binding_entry_add_signal (binding_set, keyval, 0,
322 GTK_TYPE_SCROLL_TYPE, scroll,
323 G_TYPE_BOOLEAN, FALSE);
324 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
326 GTK_TYPE_SCROLL_TYPE, scroll,
327 G_TYPE_BOOLEAN, FALSE);
331 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
333 GObjectClass *gobject_class;
334 HildonWindowClass *hildon_window_class;
335 ModestWindowClass *modest_window_class;
336 GtkBindingSet *binding_set;
338 gobject_class = (GObjectClass*) klass;
339 hildon_window_class = (HildonWindowClass *) klass;
340 modest_window_class = (ModestWindowClass *) klass;
342 parent_class = g_type_class_peek_parent (klass);
343 gobject_class->finalize = modest_msg_view_window_finalize;
345 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
346 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
347 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
348 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
349 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
350 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
352 modest_window_class->save_state_func = save_state;
354 klass->scroll_child = modest_msg_view_window_scroll_child;
356 signals[MSG_CHANGED_SIGNAL] =
357 g_signal_new ("msg-changed",
358 G_TYPE_FROM_CLASS (gobject_class),
360 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
362 modest_marshal_VOID__POINTER_POINTER,
363 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
365 signals[SCROLL_CHILD_SIGNAL] =
366 g_signal_new ("scroll-child",
367 G_TYPE_FROM_CLASS (gobject_class),
368 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
369 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
371 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
372 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
374 binding_set = gtk_binding_set_by_class (klass);
375 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
376 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
377 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
378 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
379 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
380 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
382 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
386 static void modest_header_view_observer_init(
387 ModestHeaderViewObserverIface *iface_class)
389 iface_class->update_func = modest_msg_view_window_update_model_replaced;
393 modest_msg_view_window_init (ModestMsgViewWindow *obj)
395 ModestMsgViewWindowPrivate *priv;
396 ModestWindowPrivate *parent_priv = NULL;
397 GtkActionGroup *action_group = NULL;
398 GError *error = NULL;
399 GdkPixbuf *window_icon;
401 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
402 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
403 parent_priv->ui_manager = gtk_ui_manager_new();
405 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
406 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
408 /* Add common actions */
409 gtk_action_group_add_actions (action_group,
410 modest_action_entries,
411 G_N_ELEMENTS (modest_action_entries),
413 gtk_action_group_add_toggle_actions (action_group,
414 msg_view_toggle_action_entries,
415 G_N_ELEMENTS (msg_view_toggle_action_entries),
418 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
419 g_object_unref (action_group);
421 /* Load the UI definition */
422 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
425 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
426 g_error_free (error);
431 /* Add accelerators */
432 gtk_window_add_accel_group (GTK_WINDOW (obj),
433 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
435 priv->is_search_result = FALSE;
436 priv->is_outbox = FALSE;
438 priv->msg_view = NULL;
439 priv->header_model = NULL;
440 priv->header_folder_id = NULL;
441 priv->clipboard_change_handler = 0;
442 priv->queue_change_handler = 0;
443 priv->account_removed_handler = 0;
444 priv->row_changed_handler = 0;
445 priv->row_deleted_handler = 0;
446 priv->row_inserted_handler = 0;
447 priv->rows_reordered_handler = 0;
448 priv->progress_hint = FALSE;
449 priv->fetching_images = 0;
451 priv->optimized_view = FALSE;
452 priv->purge_timeout = 0;
453 priv->remove_attachment_banner = NULL;
454 priv->msg_uid = NULL;
455 priv->other_body = NULL;
457 priv->sighandlers = NULL;
460 init_window (MODEST_MSG_VIEW_WINDOW(obj));
462 /* Set window icon */
463 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
465 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
466 g_object_unref (window_icon);
469 hildon_program_add_window (hildon_program_get_instance(),
476 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
478 ModestMsgViewWindowPrivate *priv = NULL;
480 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
482 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
484 set_progress_hint (self, TRUE);
490 update_progress_hint (ModestMsgViewWindow *self)
492 ModestMsgViewWindowPrivate *priv;
493 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
495 if (GTK_WIDGET_VISIBLE (self)) {
496 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self),
497 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
502 set_progress_hint (ModestMsgViewWindow *self,
505 ModestWindowPrivate *parent_priv;
506 ModestMsgViewWindowPrivate *priv;
508 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
510 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
511 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
513 /* Sets current progress hint */
514 priv->progress_hint = enabled;
516 update_progress_hint (self);
522 init_window (ModestMsgViewWindow *obj)
524 GtkWidget *main_vbox;
525 ModestMsgViewWindowPrivate *priv;
527 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
529 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
530 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
531 main_vbox = gtk_vbox_new (FALSE, 6);
532 priv->main_scroll = hildon_pannable_area_new ();
533 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
534 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
535 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
537 /* NULL-ize fields if the window is destroyed */
538 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
540 gtk_widget_show_all (GTK_WIDGET(main_vbox));
544 modest_msg_view_window_disconnect_signals (ModestWindow *self)
546 ModestMsgViewWindowPrivate *priv;
547 GtkWidget *header_view = NULL;
548 GtkWindow *parent_window = NULL;
550 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
552 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
553 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
554 priv->clipboard_change_handler))
555 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
556 priv->clipboard_change_handler);
558 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
559 priv->queue_change_handler))
560 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
561 priv->queue_change_handler);
563 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
564 priv->account_removed_handler))
565 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
566 priv->account_removed_handler);
568 if (priv->header_model) {
569 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
570 priv->row_changed_handler))
571 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
572 priv->row_changed_handler);
574 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
575 priv->row_deleted_handler))
576 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
577 priv->row_deleted_handler);
579 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
580 priv->row_inserted_handler))
581 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
582 priv->row_inserted_handler);
584 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
585 priv->rows_reordered_handler))
586 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
587 priv->rows_reordered_handler);
590 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
591 priv->sighandlers = NULL;
593 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
594 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
595 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
597 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
598 MODEST_HEADER_VIEW_OBSERVER(self));
604 modest_msg_view_window_finalize (GObject *obj)
606 ModestMsgViewWindowPrivate *priv;
608 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
610 /* Sanity check: shouldn't be needed, the window mgr should
611 call this function before */
612 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
614 if (priv->other_body != NULL) {
615 g_object_unref (priv->other_body);
616 priv->other_body = NULL;
619 if (priv->header_model != NULL) {
620 g_object_unref (priv->header_model);
621 priv->header_model = NULL;
624 if (priv->remove_attachment_banner) {
625 gtk_widget_destroy (priv->remove_attachment_banner);
626 g_object_unref (priv->remove_attachment_banner);
627 priv->remove_attachment_banner = NULL;
630 if (priv->purge_timeout > 0) {
631 g_source_remove (priv->purge_timeout);
632 priv->purge_timeout = 0;
635 if (priv->row_reference) {
636 gtk_tree_row_reference_free (priv->row_reference);
637 priv->row_reference = NULL;
640 if (priv->next_row_reference) {
641 gtk_tree_row_reference_free (priv->next_row_reference);
642 priv->next_row_reference = NULL;
646 g_free (priv->msg_uid);
647 priv->msg_uid = NULL;
650 G_OBJECT_CLASS(parent_class)->finalize (obj);
654 select_next_valid_row (GtkTreeModel *model,
655 GtkTreeRowReference **row_reference,
659 GtkTreeIter tmp_iter;
661 GtkTreePath *next = NULL;
662 gboolean retval = FALSE, finished;
664 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
666 path = gtk_tree_row_reference_get_path (*row_reference);
667 gtk_tree_model_get_iter (model, &tmp_iter, path);
668 gtk_tree_row_reference_free (*row_reference);
669 *row_reference = NULL;
673 TnyHeader *header = NULL;
675 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
676 gtk_tree_model_get (model, &tmp_iter,
677 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
681 if (msg_is_visible (header, is_outbox)) {
682 next = gtk_tree_model_get_path (model, &tmp_iter);
683 *row_reference = gtk_tree_row_reference_new (model, next);
684 gtk_tree_path_free (next);
688 g_object_unref (header);
691 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
692 next = gtk_tree_model_get_path (model, &tmp_iter);
694 /* Ensure that we are not selecting the same */
695 if (gtk_tree_path_compare (path, next) != 0) {
696 gtk_tree_model_get (model, &tmp_iter,
697 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
700 if (msg_is_visible (header, is_outbox)) {
701 *row_reference = gtk_tree_row_reference_new (model, next);
705 g_object_unref (header);
709 /* If we ended up in the same message
710 then there is no valid next
714 gtk_tree_path_free (next);
716 /* If there are no more messages and we don't
717 want to start again in the first one then
718 there is no valid next message */
724 gtk_tree_path_free (path);
729 /* TODO: This should be in _init(), with the parameters as properties. */
731 modest_msg_view_window_construct (ModestMsgViewWindow *self,
732 const gchar *modest_account_name,
733 const gchar *mailbox,
734 const gchar *msg_uid)
737 ModestMsgViewWindowPrivate *priv = NULL;
738 ModestWindowPrivate *parent_priv = NULL;
739 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
740 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
742 obj = G_OBJECT (self);
743 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
744 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
746 priv->msg_uid = g_strdup (msg_uid);
749 parent_priv->menubar = NULL;
751 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
752 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
755 /* Add common dimming rules */
756 modest_dimming_rules_group_add_rules (toolbar_rules_group,
757 modest_msg_view_toolbar_dimming_entries,
758 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
759 MODEST_WINDOW (self));
760 modest_dimming_rules_group_add_rules (clipboard_rules_group,
761 modest_msg_view_clipboard_dimming_entries,
762 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
763 MODEST_WINDOW (self));
765 /* Insert dimming rules group for this window */
766 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
767 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
768 g_object_unref (toolbar_rules_group);
769 g_object_unref (clipboard_rules_group);
771 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
773 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);
774 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
775 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
776 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
777 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
778 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
779 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
780 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
781 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
782 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
783 G_CALLBACK (modest_ui_actions_on_details), obj);
784 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
785 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
786 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
787 G_CALLBACK (on_fetch_image), obj);
789 g_signal_connect (G_OBJECT (obj), "key-release-event",
790 G_CALLBACK (modest_msg_view_window_key_event),
793 g_signal_connect (G_OBJECT (obj), "key-press-event",
794 G_CALLBACK (modest_msg_view_window_key_event),
797 g_signal_connect (G_OBJECT (obj), "move-focus",
798 G_CALLBACK (on_move_focus), obj);
800 g_signal_connect (G_OBJECT (obj), "map-event",
801 G_CALLBACK (_modest_msg_view_window_map_event),
804 /* Mail Operation Queue */
805 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
807 G_CALLBACK (on_queue_changed),
810 /* Account manager */
811 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
813 G_CALLBACK(on_account_removed),
816 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
817 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
819 /* First add out toolbar ... */
820 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
822 /* ... and later the find toolbar. This way find toolbar will
823 be shown over the other */
824 priv->find_toolbar = hildon_find_toolbar_new (NULL);
825 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
826 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
827 g_signal_connect (G_OBJECT (priv->find_toolbar), "close",
828 G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
829 g_signal_connect (G_OBJECT (priv->find_toolbar), "search",
830 G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
831 priv->last_search = NULL;
833 /* Init the clipboard actions dim status */
834 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
836 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
841 /* FIXME: parameter checks */
843 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
844 const gchar *modest_account_name,
845 const gchar *mailbox,
846 const gchar *msg_uid,
848 GtkTreeRowReference *row_reference)
850 ModestMsgViewWindow *window = NULL;
851 ModestMsgViewWindowPrivate *priv = NULL;
852 TnyFolder *header_folder = NULL;
853 ModestHeaderView *header_view = NULL;
854 ModestWindowMgr *mgr = NULL;
857 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
860 mgr = modest_runtime_get_window_mgr ();
861 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
862 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
864 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
866 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
868 /* Remember the message list's TreeModel so we can detect changes
869 * and change the list selection when necessary: */
870 header_folder = modest_header_view_get_folder (header_view);
872 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
873 TNY_FOLDER_TYPE_OUTBOX);
874 priv->header_folder_id = tny_folder_get_id (header_folder);
875 g_object_unref(header_folder);
878 /* Setup row references and connect signals */
879 priv->header_model = g_object_ref (model);
882 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
883 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
884 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
886 priv->row_reference = NULL;
887 priv->next_row_reference = NULL;
890 /* Connect signals */
891 priv->row_changed_handler =
892 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
893 G_CALLBACK(modest_msg_view_window_on_row_changed),
895 priv->row_deleted_handler =
896 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
897 G_CALLBACK(modest_msg_view_window_on_row_deleted),
899 priv->row_inserted_handler =
900 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
901 G_CALLBACK(modest_msg_view_window_on_row_inserted),
903 priv->rows_reordered_handler =
904 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
905 G_CALLBACK(modest_msg_view_window_on_row_reordered),
908 if (header_view != NULL){
909 modest_header_view_add_observer(header_view,
910 MODEST_HEADER_VIEW_OBSERVER(window));
913 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
914 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
915 update_branding (MODEST_MSG_VIEW_WINDOW (window));
917 /* gtk_widget_show_all (GTK_WIDGET (window)); */
918 modest_msg_view_window_update_priority (window);
919 /* Check dimming rules */
920 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
921 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
922 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
924 return MODEST_WINDOW(window);
928 modest_msg_view_window_new_from_uid (const gchar *modest_account_name,
929 const gchar *mailbox,
930 const gchar *msg_uid)
932 ModestMsgViewWindow *window = NULL;
933 ModestMsgViewWindowPrivate *priv = NULL;
934 ModestWindowMgr *mgr = NULL;
936 TnyAccount *account = NULL;
938 mgr = modest_runtime_get_window_mgr ();
939 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
940 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
942 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
944 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
948 is_merge = g_str_has_prefix (msg_uid, "merge:");
950 /* Get the account */
952 account = tny_account_store_find_account (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
956 if (is_merge || account) {
957 TnyFolder *folder = NULL;
959 /* Try to get the message, if it's already downloaded
960 we don't need to connect */
962 folder = modest_tny_folder_store_find_folder_from_uri (TNY_FOLDER_STORE (account), msg_uid);
964 ModestTnyAccountStore *account_store;
965 ModestTnyLocalFoldersAccount *local_folders_account;
967 account_store = modest_runtime_get_account_store ();
968 local_folders_account = MODEST_TNY_LOCAL_FOLDERS_ACCOUNT (
969 modest_tny_account_store_get_local_folders_account (account_store));
970 folder = modest_tny_local_folders_account_get_merged_outbox (local_folders_account);
971 g_object_unref (local_folders_account);
975 gboolean device_online;
977 device = modest_runtime_get_device();
978 device_online = tny_device_is_online (device);
980 message_reader (window, priv, NULL, msg_uid, folder, NULL);
982 TnyMsg *msg = tny_folder_find_msg (folder, msg_uid, NULL);
984 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
985 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
986 update_branding (MODEST_MSG_VIEW_WINDOW (window));
987 g_object_unref (msg);
989 message_reader (window, priv, NULL, msg_uid, folder, NULL);
992 g_object_unref (folder);
997 /* Check dimming rules */
998 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
999 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1000 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1002 return MODEST_WINDOW(window);
1006 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1007 const gchar *modest_account_name,
1008 const gchar *mailbox,
1009 const gchar *msg_uid,
1010 GtkTreeRowReference *row_reference)
1012 ModestMsgViewWindow *window = NULL;
1013 ModestMsgViewWindowPrivate *priv = NULL;
1014 TnyFolder *header_folder = NULL;
1015 ModestWindowMgr *mgr = NULL;
1019 mgr = modest_runtime_get_window_mgr ();
1020 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1021 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 the message list's TreeModel so we can detect changes
1028 * and change the list selection when necessary: */
1030 if (header_view != NULL){
1031 header_folder = modest_header_view_get_folder(header_view);
1032 /* This could happen if the header folder was
1033 unseleted before opening this msg window (for
1034 example if the user selects an account in the
1035 folder view of the main window */
1036 if (header_folder) {
1037 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1038 TNY_FOLDER_TYPE_OUTBOX);
1039 priv->header_folder_id = tny_folder_get_id(header_folder);
1040 g_object_unref(header_folder);
1044 /* Setup row references and connect signals */
1045 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1046 g_object_ref (priv->header_model);
1048 if (row_reference) {
1049 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1050 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1051 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1053 priv->row_reference = NULL;
1054 priv->next_row_reference = NULL;
1057 /* Connect signals */
1058 priv->row_changed_handler =
1059 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1060 G_CALLBACK(modest_msg_view_window_on_row_changed),
1062 priv->row_deleted_handler =
1063 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1064 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1066 priv->row_inserted_handler =
1067 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1068 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1070 priv->rows_reordered_handler =
1071 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1072 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1075 if (header_view != NULL){
1076 modest_header_view_add_observer(header_view,
1077 MODEST_HEADER_VIEW_OBSERVER(window));
1080 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1081 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1083 path = gtk_tree_row_reference_get_path (row_reference);
1084 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1086 gtk_tree_model_get (priv->header_model, &iter,
1087 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1089 message_reader (window, priv, header, NULL, NULL, row_reference);
1090 g_object_unref (header);
1092 gtk_tree_path_free (path);
1094 /* Check dimming rules */
1095 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1096 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1097 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1099 return MODEST_WINDOW(window);
1103 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1104 const gchar *modest_account_name,
1105 const gchar *mailbox,
1106 const gchar *msg_uid)
1108 ModestMsgViewWindow *window = NULL;
1109 ModestMsgViewWindowPrivate *priv = NULL;
1110 ModestWindowMgr *mgr = NULL;
1112 mgr = modest_runtime_get_window_mgr ();
1113 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1114 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1115 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1117 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1119 /* Remember that this is a search result,
1120 * so we can disable some UI appropriately: */
1121 priv->is_search_result = TRUE;
1123 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1124 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1126 update_window_title (window);
1127 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1128 modest_msg_view_window_update_priority (window);
1130 /* Check dimming rules */
1131 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1132 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1133 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1135 return MODEST_WINDOW(window);
1139 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1141 ModestMsgViewWindowPrivate *priv = NULL;
1143 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1144 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1146 return (priv->other_body != NULL);
1150 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1151 TnyMimePart *other_body,
1152 const gchar *modest_account_name,
1153 const gchar *mailbox,
1154 const gchar *msg_uid)
1156 GObject *obj = NULL;
1157 ModestMsgViewWindowPrivate *priv;
1158 ModestWindowMgr *mgr = NULL;
1160 g_return_val_if_fail (msg, NULL);
1161 mgr = modest_runtime_get_window_mgr ();
1162 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1163 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1164 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1165 modest_account_name, mailbox, msg_uid);
1168 priv->other_body = g_object_ref (other_body);
1169 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1171 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1173 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1174 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1176 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1178 /* Check dimming rules */
1179 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1180 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1181 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1183 return MODEST_WINDOW(obj);
1187 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1188 const gchar *modest_account_name,
1189 const gchar *mailbox,
1190 const gchar *msg_uid)
1192 return modest_msg_view_window_new_with_other_body (msg, NULL, modest_account_name, mailbox, msg_uid);
1196 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1199 ModestMsgViewWindow *window)
1201 check_dimming_rules_after_change (window);
1205 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1207 ModestMsgViewWindow *window)
1209 check_dimming_rules_after_change (window);
1211 /* The window could have dissapeared */
1214 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1216 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1217 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1221 /* On insertions we check if the folder still has the message we are
1222 * showing or do not. If do not, we do nothing. Which means we are still
1223 * not attached to any header folder and thus next/prev buttons are
1224 * still dimmed. Once the message that is shown by msg-view is found, the
1225 * new model of header-view will be attached and the references will be set.
1226 * On each further insertions dimming rules will be checked. However
1227 * this requires extra CPU time at least works.
1228 * (An message might be deleted from TnyFolder and thus will not be
1229 * inserted into the model again for example if it is removed by the
1230 * imap server and the header view is refreshed.)
1233 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1234 GtkTreePath *tree_path,
1235 GtkTreeIter *tree_iter,
1236 ModestMsgViewWindow *window)
1238 ModestMsgViewWindowPrivate *priv = NULL;
1239 TnyHeader *header = NULL;
1241 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1242 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1244 g_assert (model == priv->header_model);
1246 /* Check if the newly inserted message is the same we are actually
1247 * showing. IF not, we should remain detached from the header model
1248 * and thus prev and next toolbar buttons should remain dimmed. */
1249 gtk_tree_model_get (model, tree_iter,
1250 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1253 if (TNY_IS_HEADER (header)) {
1256 uid = modest_tny_folder_get_header_unique_id (header);
1257 if (!g_str_equal(priv->msg_uid, uid)) {
1258 check_dimming_rules_after_change (window);
1260 g_object_unref (G_OBJECT(header));
1264 g_object_unref(G_OBJECT(header));
1267 if (priv->row_reference) {
1268 gtk_tree_row_reference_free (priv->row_reference);
1271 /* Setup row_reference for the actual msg. */
1272 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1273 if (priv->row_reference == NULL) {
1274 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1278 /* Now set up next_row_reference. */
1279 if (priv->next_row_reference) {
1280 gtk_tree_row_reference_free (priv->next_row_reference);
1283 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1284 select_next_valid_row (priv->header_model,
1285 &(priv->next_row_reference), FALSE, priv->is_outbox);
1287 /* Connect the remaining callbacks to become able to detect
1288 * changes in header-view. */
1289 priv->row_changed_handler =
1290 g_signal_connect (priv->header_model, "row-changed",
1291 G_CALLBACK (modest_msg_view_window_on_row_changed),
1293 priv->row_deleted_handler =
1294 g_signal_connect (priv->header_model, "row-deleted",
1295 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1297 priv->rows_reordered_handler =
1298 g_signal_connect (priv->header_model, "rows-reordered",
1299 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1302 check_dimming_rules_after_change (window);
1306 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1310 ModestMsgViewWindow *window)
1312 ModestMsgViewWindowPrivate *priv = NULL;
1313 gboolean already_changed = FALSE;
1315 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1317 /* If the current row was reordered select the proper next
1318 valid row. The same if the next row reference changes */
1319 if (priv->row_reference &&
1320 gtk_tree_row_reference_valid (priv->row_reference)) {
1322 path = gtk_tree_row_reference_get_path (priv->row_reference);
1323 if (gtk_tree_path_compare (path, arg1) == 0) {
1324 if (priv->next_row_reference) {
1325 gtk_tree_row_reference_free (priv->next_row_reference);
1327 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1328 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1329 already_changed = TRUE;
1331 gtk_tree_path_free (path);
1333 if (!already_changed &&
1334 priv->next_row_reference &&
1335 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1337 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1338 if (gtk_tree_path_compare (path, arg1) == 0) {
1339 if (priv->next_row_reference) {
1340 gtk_tree_row_reference_free (priv->next_row_reference);
1342 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1343 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1345 gtk_tree_path_free (path);
1347 check_dimming_rules_after_change (window);
1350 /* The modest_msg_view_window_update_model_replaced implements update
1351 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1352 * actually belongs to the header-view is the same as the TnyFolder of
1353 * the message of msg-view or not. If they are different, there is
1354 * nothing to do. If they are the same, then the model has replaced and
1355 * the reference in msg-view shall be replaced from the old model to
1356 * the new model. In this case the view will be detached from it's
1357 * header folder. From this point the next/prev buttons are dimmed.
1360 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1361 GtkTreeModel *model,
1362 const gchar *tny_folder_id)
1364 ModestMsgViewWindowPrivate *priv = NULL;
1365 ModestMsgViewWindow *window = NULL;
1367 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1368 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1370 window = MODEST_MSG_VIEW_WINDOW(observer);
1371 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1373 /* If there is an other folder in the header-view then we do
1374 * not care about it's model (msg list). Else if the
1375 * header-view shows the folder the msg shown by us is in, we
1376 * shall replace our model reference and make some check. */
1377 if(model == NULL || tny_folder_id == NULL ||
1378 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1381 /* Model is changed(replaced), so we should forget the old
1382 * one. Because there might be other references and there
1383 * might be some change on the model even if we unreferenced
1384 * it, we need to disconnect our signals here. */
1385 if (priv->header_model) {
1386 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1387 priv->row_changed_handler))
1388 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1389 priv->row_changed_handler);
1390 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1391 priv->row_deleted_handler))
1392 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1393 priv->row_deleted_handler);
1394 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1395 priv->row_inserted_handler))
1396 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1397 priv->row_inserted_handler);
1398 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1399 priv->rows_reordered_handler))
1400 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1401 priv->rows_reordered_handler);
1404 if (priv->row_reference)
1405 gtk_tree_row_reference_free (priv->row_reference);
1406 if (priv->next_row_reference)
1407 gtk_tree_row_reference_free (priv->next_row_reference);
1408 g_object_unref(priv->header_model);
1411 priv->row_changed_handler = 0;
1412 priv->row_deleted_handler = 0;
1413 priv->row_inserted_handler = 0;
1414 priv->rows_reordered_handler = 0;
1415 priv->next_row_reference = NULL;
1416 priv->row_reference = NULL;
1417 priv->header_model = NULL;
1420 priv->header_model = g_object_ref (model);
1422 /* Also we must connect to the new model for row insertions.
1423 * Only for insertions now. We will need other ones only after
1424 * the msg is show by msg-view is added to the new model. */
1425 priv->row_inserted_handler =
1426 g_signal_connect (priv->header_model, "row-inserted",
1427 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1430 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1431 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1435 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1437 ModestMsgViewWindowPrivate *priv= NULL;
1439 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1440 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1442 return priv->progress_hint;
1446 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1448 ModestMsgViewWindowPrivate *priv= NULL;
1450 TnyHeader *header = NULL;
1451 GtkTreePath *path = NULL;
1454 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1455 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1457 /* If the message was not obtained from a treemodel,
1458 * for instance if it was opened directly by the search UI:
1460 if (priv->header_model == NULL ||
1461 priv->row_reference == NULL ||
1462 !gtk_tree_row_reference_valid (priv->row_reference)) {
1463 msg = modest_msg_view_window_get_message (self);
1465 header = tny_msg_get_header (msg);
1466 g_object_unref (msg);
1471 /* Get iter of the currently selected message in the header view: */
1472 path = gtk_tree_row_reference_get_path (priv->row_reference);
1473 g_return_val_if_fail (path != NULL, NULL);
1474 gtk_tree_model_get_iter (priv->header_model,
1478 /* Get current message header */
1479 gtk_tree_model_get (priv->header_model, &iter,
1480 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1483 gtk_tree_path_free (path);
1488 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1490 ModestMsgViewWindowPrivate *priv;
1492 g_return_val_if_fail (self, NULL);
1494 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1496 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1500 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1502 ModestMsgViewWindowPrivate *priv;
1504 g_return_val_if_fail (self, NULL);
1506 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1508 return (const gchar*) priv->msg_uid;
1512 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1515 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1516 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1517 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1521 is_active = gtk_toggle_action_get_active (toggle);
1524 gtk_widget_show (priv->find_toolbar);
1525 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1527 gtk_widget_hide (priv->find_toolbar);
1528 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1531 /* update the toggle buttons status */
1532 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1534 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1539 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1540 ModestMsgViewWindow *obj)
1542 GtkToggleAction *toggle;
1543 ModestWindowPrivate *parent_priv;
1544 ModestMsgViewWindowPrivate *priv;
1546 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1547 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1549 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1550 gtk_toggle_action_set_active (toggle, FALSE);
1551 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1555 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1556 ModestMsgViewWindow *obj)
1558 gchar *current_search;
1559 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1561 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1562 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1566 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1568 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1569 g_free (current_search);
1570 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
1574 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1576 g_free (priv->last_search);
1577 priv->last_search = g_strdup (current_search);
1578 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1581 hildon_banner_show_information (NULL, NULL,
1582 _HL("ckct_ib_find_no_matches"));
1583 g_free (priv->last_search);
1584 priv->last_search = NULL;
1586 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1589 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1590 hildon_banner_show_information (NULL, NULL,
1591 _HL("ckct_ib_find_search_complete"));
1592 g_free (priv->last_search);
1593 priv->last_search = NULL;
1595 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1599 g_free (current_search);
1604 modest_msg_view_window_set_zoom (ModestWindow *window,
1607 ModestMsgViewWindowPrivate *priv;
1608 ModestWindowPrivate *parent_priv;
1610 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1612 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1613 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1614 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1619 modest_msg_view_window_get_zoom (ModestWindow *window)
1621 ModestMsgViewWindowPrivate *priv;
1623 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1625 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1626 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1630 modest_msg_view_window_zoom_plus (ModestWindow *window)
1633 ModestMsgViewWindowPrivate *priv;
1637 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1638 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1640 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1642 if (zoom_level >= 2.0) {
1643 hildon_banner_show_information (NULL, NULL,
1644 _CS("ckct_ib_max_zoom_level_reached"));
1646 } else if (zoom_level >= 1.5) {
1648 } else if (zoom_level >= 1.2) {
1650 } else if (zoom_level >= 1.0) {
1652 } else if (zoom_level >= 0.8) {
1654 } else if (zoom_level >= 0.5) {
1660 /* set zoom level */
1661 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1662 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1663 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1664 g_free (banner_text);
1665 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1671 modest_msg_view_window_zoom_minus (ModestWindow *window)
1674 ModestMsgViewWindowPrivate *priv;
1678 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1679 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1681 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1683 if (zoom_level <= 0.5) {
1684 hildon_banner_show_information (NULL, NULL,
1685 _CS("ckct_ib_min_zoom_level_reached"));
1687 } else if (zoom_level <= 0.8) {
1689 } else if (zoom_level <= 1.0) {
1691 } else if (zoom_level <= 1.2) {
1693 } else if (zoom_level <= 1.5) {
1695 } else if (zoom_level <= 2.0) {
1701 /* set zoom level */
1702 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1703 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1704 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1705 g_free (banner_text);
1706 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1713 modest_msg_view_window_key_event (GtkWidget *window,
1719 focus = gtk_window_get_focus (GTK_WINDOW (window));
1721 /* for the find toolbar case */
1722 if (focus && GTK_IS_ENTRY (focus)) {
1723 if (event->keyval == GDK_BackSpace) {
1725 copy = gdk_event_copy ((GdkEvent *) event);
1726 gtk_widget_event (focus, copy);
1727 gdk_event_free (copy);
1732 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1733 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1734 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1735 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1736 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1737 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1738 /* ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); */
1739 /* gboolean return_value; */
1741 if (event->type == GDK_KEY_PRESS) {
1742 GtkScrollType scroll_type;
1744 switch (event->keyval) {
1747 scroll_type = GTK_SCROLL_STEP_UP; break;
1750 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1752 case GDK_KP_Page_Up:
1753 scroll_type = GTK_SCROLL_PAGE_UP; break;
1755 case GDK_KP_Page_Down:
1756 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1759 scroll_type = GTK_SCROLL_START; break;
1762 scroll_type = GTK_SCROLL_END; break;
1763 default: scroll_type = GTK_SCROLL_NONE;
1766 /* g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", */
1767 /* scroll_type, FALSE, &return_value); */
1778 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1781 ModestMsgViewWindowPrivate *priv;
1782 GtkTreeIter tmp_iter;
1783 gboolean is_last_selected;
1785 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1786 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1788 /*if no model (so no rows at all), then virtually we are the last*/
1789 if (!priv->header_model || !priv->row_reference)
1792 if (!gtk_tree_row_reference_valid (priv->row_reference))
1795 path = gtk_tree_row_reference_get_path (priv->row_reference);
1799 is_last_selected = TRUE;
1800 while (is_last_selected) {
1802 gtk_tree_path_next (path);
1803 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1805 gtk_tree_model_get (priv->header_model, &tmp_iter,
1806 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1809 if (msg_is_visible (header, priv->is_outbox))
1810 is_last_selected = FALSE;
1811 g_object_unref(G_OBJECT(header));
1814 gtk_tree_path_free (path);
1815 return is_last_selected;
1819 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1821 ModestMsgViewWindowPrivate *priv;
1823 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1824 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1826 return priv->header_model != NULL;
1830 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1832 ModestMsgViewWindowPrivate *priv;
1834 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1835 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1837 return priv->is_search_result;
1841 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1843 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1845 if (!check_outbox) {
1848 ModestTnySendQueueStatus status;
1849 status = modest_tny_all_send_queues_get_msg_status (header);
1850 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1851 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1856 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1859 ModestMsgViewWindowPrivate *priv;
1860 gboolean is_first_selected;
1861 GtkTreeIter tmp_iter;
1863 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1864 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1866 /*if no model (so no rows at all), then virtually we are the first*/
1867 if (!priv->header_model || !priv->row_reference)
1870 if (!gtk_tree_row_reference_valid (priv->row_reference))
1873 path = gtk_tree_row_reference_get_path (priv->row_reference);
1877 is_first_selected = TRUE;
1878 while (is_first_selected) {
1880 if(!gtk_tree_path_prev (path))
1882 /* Here the 'if' is needless for logic, but let make sure
1883 * iter is valid for gtk_tree_model_get. */
1884 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1886 gtk_tree_model_get (priv->header_model, &tmp_iter,
1887 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1890 if (msg_is_visible (header, priv->is_outbox))
1891 is_first_selected = FALSE;
1892 g_object_unref(G_OBJECT(header));
1895 gtk_tree_path_free (path);
1896 return is_first_selected;
1903 GtkTreeRowReference *row_reference;
1907 message_reader_performer (gboolean canceled,
1909 GtkWindow *parent_window,
1910 TnyAccount *account,
1913 ModestMailOperation *mail_op = NULL;
1914 MsgReaderInfo *info;
1916 info = (MsgReaderInfo *) user_data;
1917 if (canceled || err) {
1918 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1922 /* Register the header - it'll be unregistered in the callback */
1924 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1926 /* New mail operation */
1927 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1928 modest_ui_actions_disk_operations_error_handler,
1931 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1933 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1935 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1936 g_object_unref (mail_op);
1938 /* Update dimming rules */
1939 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1940 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1943 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1944 g_free (info->msg_uid);
1946 g_object_unref (info->folder);
1948 g_object_unref (info->header);
1949 g_slice_free (MsgReaderInfo, info);
1954 * Reads the message whose summary item is @header. It takes care of
1955 * several things, among others:
1957 * If the message was not previously downloaded then ask the user
1958 * before downloading. If there is no connection launch the connection
1959 * dialog. Update toolbar dimming rules.
1961 * Returns: TRUE if the mail operation was started, otherwise if the
1962 * user do not want to download the message, or if the user do not
1963 * want to connect, then the operation is not issued
1966 message_reader (ModestMsgViewWindow *window,
1967 ModestMsgViewWindowPrivate *priv,
1969 const gchar *msg_uid,
1971 GtkTreeRowReference *row_reference)
1973 ModestWindowMgr *mgr;
1974 TnyAccount *account;
1975 MsgReaderInfo *info;
1977 /* We set the header from model while we're loading */
1978 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
1979 gtk_window_set_title (GTK_WINDOW (window), _CS("ckdg_pb_updating"));
1982 g_object_ref (folder);
1984 mgr = modest_runtime_get_window_mgr ();
1985 /* Msg download completed */
1986 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1988 /* Ask the user if he wants to download the message if
1990 if (!tny_device_is_online (modest_runtime_get_device())) {
1991 GtkResponseType response;
1993 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1994 _("mcen_nc_get_msg"));
1995 if (response == GTK_RESPONSE_CANCEL) {
1996 update_window_title (window);
2001 folder = tny_header_get_folder (header);
2003 info = g_slice_new (MsgReaderInfo);
2004 info->msg_uid = g_strdup (msg_uid);
2006 info->header = g_object_ref (header);
2008 info->header = NULL;
2010 info->folder = g_object_ref (folder);
2012 info->folder = NULL;
2013 if (row_reference) {
2014 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2016 info->row_reference = NULL;
2019 /* Offer the connection dialog if necessary */
2020 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
2022 TNY_FOLDER_STORE (folder),
2023 message_reader_performer,
2025 g_object_unref (folder);
2031 folder = tny_header_get_folder (header);
2033 account = tny_folder_get_account (folder);
2034 info = g_slice_new (MsgReaderInfo);
2035 info->msg_uid = g_strdup (msg_uid);
2037 info->folder = g_object_ref (folder);
2039 info->folder = NULL;
2041 info->header = g_object_ref (header);
2043 info->header = NULL;
2045 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2047 info->row_reference = NULL;
2049 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
2050 g_object_unref (account);
2051 g_object_unref (folder);
2057 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2059 ModestMsgViewWindowPrivate *priv;
2060 GtkTreePath *path= NULL;
2061 GtkTreeIter tmp_iter;
2063 gboolean retval = TRUE;
2064 GtkTreeRowReference *row_reference = NULL;
2066 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2067 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2069 if (!priv->row_reference)
2072 /* Update the next row reference if it's not valid. This could
2073 happen if for example the header which it was pointing to,
2074 was deleted. The best place to do it is in the row-deleted
2075 handler but the tinymail model do not work like the glib
2076 tree models and reports the deletion when the row is still
2078 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2079 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2080 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2081 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2084 if (priv->next_row_reference)
2085 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2089 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2091 gtk_tree_model_get_iter (priv->header_model,
2094 gtk_tree_path_free (path);
2096 gtk_tree_model_get (priv->header_model, &tmp_iter,
2097 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2100 /* Read the message & show it */
2101 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2104 gtk_tree_row_reference_free (row_reference);
2107 g_object_unref (header);
2113 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2115 ModestMsgViewWindowPrivate *priv = NULL;
2117 gboolean finished = FALSE;
2118 gboolean retval = FALSE;
2120 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2121 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2123 /* Return inmediatly if there is no header model */
2124 if (!priv->header_model || !priv->row_reference)
2127 path = gtk_tree_row_reference_get_path (priv->row_reference);
2128 while (!finished && gtk_tree_path_prev (path)) {
2132 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2133 gtk_tree_model_get (priv->header_model, &iter,
2134 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2138 if (msg_is_visible (header, priv->is_outbox)) {
2139 GtkTreeRowReference *row_reference;
2140 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2141 /* Read the message & show it */
2142 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2143 gtk_tree_row_reference_free (row_reference);
2147 g_object_unref (header);
2151 gtk_tree_path_free (path);
2156 view_msg_cb (ModestMailOperation *mail_op,
2163 ModestMsgViewWindow *self = NULL;
2164 ModestMsgViewWindowPrivate *priv = NULL;
2165 GtkTreeRowReference *row_reference = NULL;
2167 /* Unregister the header (it was registered before creating the mail operation) */
2168 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2170 row_reference = (GtkTreeRowReference *) user_data;
2173 gtk_tree_row_reference_free (row_reference);
2174 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2176 /* Restore window title */
2177 update_window_title (self);
2178 g_object_unref (self);
2183 /* If there was any error */
2184 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2186 gtk_tree_row_reference_free (row_reference);
2187 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2189 /* Restore window title */
2190 update_window_title (self);
2191 g_object_unref (self);
2196 /* Get the window */
2197 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2198 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2199 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2201 /* Update the row reference */
2202 if (priv->row_reference != NULL) {
2203 gtk_tree_row_reference_free (priv->row_reference);
2204 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
2205 if (priv->next_row_reference != NULL) {
2206 gtk_tree_row_reference_free (priv->next_row_reference);
2208 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2209 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2212 /* Mark header as read */
2213 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2214 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2216 /* Set new message */
2217 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2218 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2219 modest_msg_view_window_update_priority (self);
2220 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2221 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2222 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2225 /* Set the new message uid of the window */
2226 if (priv->msg_uid) {
2227 g_free (priv->msg_uid);
2228 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2231 /* Notify the observers */
2232 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2233 0, priv->header_model, priv->row_reference);
2236 g_object_unref (self);
2238 gtk_tree_row_reference_free (row_reference);
2242 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2244 ModestMsgViewWindowPrivate *priv;
2246 TnyFolderType folder_type;
2248 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2250 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2252 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2256 folder = tny_msg_get_folder (msg);
2258 folder_type = modest_tny_folder_guess_folder_type (folder);
2259 g_object_unref (folder);
2261 g_object_unref (msg);
2269 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2271 ModestMsgViewWindowPrivate *priv;
2272 TnyHeader *header = NULL;
2273 TnyHeaderFlags flags = 0;
2275 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2277 if (priv->header_model && priv->row_reference) {
2279 GtkTreePath *path = NULL;
2281 path = gtk_tree_row_reference_get_path (priv->row_reference);
2282 g_return_if_fail (path != NULL);
2283 gtk_tree_model_get_iter (priv->header_model,
2285 gtk_tree_row_reference_get_path (priv->row_reference));
2287 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2289 gtk_tree_path_free (path);
2292 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2294 header = tny_msg_get_header (msg);
2295 g_object_unref (msg);
2300 flags = tny_header_get_flags (header);
2301 g_object_unref(G_OBJECT(header));
2304 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2309 toolbar_resize (ModestMsgViewWindow *self)
2311 ModestMsgViewWindowPrivate *priv = NULL;
2312 ModestWindowPrivate *parent_priv = NULL;
2314 gint static_button_size;
2315 ModestWindowMgr *mgr;
2317 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2318 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2319 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2321 mgr = modest_runtime_get_window_mgr ();
2322 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2324 if (parent_priv->toolbar) {
2325 /* left size buttons */
2326 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2327 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2328 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2329 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2330 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
2331 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2332 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2333 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2334 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2335 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2336 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2337 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2338 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
2339 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2340 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2341 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2343 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2344 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2345 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2346 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2351 modest_msg_view_window_show_toolbar (ModestWindow *self,
2352 gboolean show_toolbar)
2354 ModestMsgViewWindowPrivate *priv = NULL;
2355 ModestWindowPrivate *parent_priv;
2357 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2358 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2360 /* Set optimized view status */
2361 priv->optimized_view = !show_toolbar;
2363 if (!parent_priv->toolbar) {
2364 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2366 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2367 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2369 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2370 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2371 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2374 hildon_window_add_toolbar (HILDON_WINDOW (self),
2375 GTK_TOOLBAR (parent_priv->toolbar));
2380 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2381 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2382 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2384 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2385 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2386 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2388 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2391 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2392 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2397 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2399 ModestMsgViewWindow *window)
2401 if (!GTK_WIDGET_VISIBLE (window))
2404 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2408 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2410 ModestMsgViewWindowPrivate *priv;
2412 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2413 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2415 return priv->progress_hint;
2419 observers_empty (ModestMsgViewWindow *self)
2422 ModestMsgViewWindowPrivate *priv;
2423 gboolean is_empty = TRUE;
2424 guint pending_ops = 0;
2426 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2427 tmp = priv->progress_widgets;
2429 /* Check all observers */
2430 while (tmp && is_empty) {
2431 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2432 is_empty = pending_ops == 0;
2434 tmp = g_slist_next(tmp);
2441 on_account_removed (TnyAccountStore *account_store,
2442 TnyAccount *account,
2445 /* Do nothing if it's a transport account, because we only
2446 show the messages of a store account */
2447 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2448 const gchar *parent_acc = NULL;
2449 const gchar *our_acc = NULL;
2451 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2452 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2454 /* Close this window if I'm showing a message of the removed account */
2455 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2456 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2461 on_mail_operation_started (ModestMailOperation *mail_op,
2464 ModestMsgViewWindow *self;
2465 ModestMailOperationTypeOperation op_type;
2467 ModestMsgViewWindowPrivate *priv;
2468 GObject *source = NULL;
2470 self = MODEST_MSG_VIEW_WINDOW (user_data);
2471 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2472 op_type = modest_mail_operation_get_type_operation (mail_op);
2473 tmp = priv->progress_widgets;
2474 source = modest_mail_operation_get_source(mail_op);
2475 if (G_OBJECT (self) == source) {
2476 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2477 set_toolbar_transfer_mode(self);
2479 modest_progress_object_add_operation (
2480 MODEST_PROGRESS_OBJECT (tmp->data),
2482 tmp = g_slist_next (tmp);
2486 g_object_unref (source);
2490 on_mail_operation_finished (ModestMailOperation *mail_op,
2493 ModestMsgViewWindow *self;
2494 ModestMailOperationTypeOperation op_type;
2496 ModestMsgViewWindowPrivate *priv;
2498 self = MODEST_MSG_VIEW_WINDOW (user_data);
2499 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2500 op_type = modest_mail_operation_get_type_operation (mail_op);
2501 tmp = priv->progress_widgets;
2503 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2505 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2507 tmp = g_slist_next (tmp);
2510 /* If no more operations are being observed, NORMAL mode is enabled again */
2511 if (observers_empty (self)) {
2512 set_progress_hint (self, FALSE);
2516 /* Update dimming rules. We have to do this right here
2517 and not in view_msg_cb because at that point the
2518 transfer mode is still enabled so the dimming rule
2519 won't let the user delete the message that has been
2520 readed for example */
2521 check_dimming_rules_after_change (self);
2526 on_queue_changed (ModestMailOperationQueue *queue,
2527 ModestMailOperation *mail_op,
2528 ModestMailOperationQueueNotification type,
2529 ModestMsgViewWindow *self)
2531 ModestMsgViewWindowPrivate *priv;
2533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2535 /* If this operations was created by another window, do nothing */
2536 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2539 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2540 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2542 "operation-started",
2543 G_CALLBACK (on_mail_operation_started),
2545 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2547 "operation-finished",
2548 G_CALLBACK (on_mail_operation_finished),
2550 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2551 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2553 "operation-started");
2554 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2556 "operation-finished");
2561 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2563 ModestMsgViewWindowPrivate *priv;
2564 TnyList *selected_attachments = NULL;
2566 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2567 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2569 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2570 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2572 return selected_attachments;
2576 ModestMsgViewWindow *self;
2578 } DecodeAsyncHelper;
2581 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2587 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2589 /* It could happen that the window was closed */
2590 if (GTK_WIDGET_VISIBLE (helper->self))
2591 set_progress_hint (helper->self, FALSE);
2593 if (cancelled || err) {
2595 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2596 modest_platform_information_banner (NULL, NULL, msg);
2602 /* make the file read-only */
2603 g_chmod(helper->file_path, 0444);
2605 /* Activate the file */
2606 modest_platform_activate_file (helper->file_path, tny_mime_part_get_content_type (mime_part));
2610 g_object_unref (helper->self);
2611 g_free (helper->file_path);
2612 g_slice_free (DecodeAsyncHelper, helper);
2616 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2617 TnyMimePart *mime_part)
2619 ModestMsgViewWindowPrivate *priv;
2620 const gchar *msg_uid;
2621 gchar *attachment_uid = NULL;
2622 gint attachment_index = 0;
2623 TnyList *attachments;
2625 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2626 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2627 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2629 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2630 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2631 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2632 g_object_unref (attachments);
2634 if (msg_uid && attachment_index >= 0) {
2635 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2638 if (mime_part == NULL) {
2639 gboolean error = FALSE;
2640 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2641 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2643 } else if (tny_list_get_length (selected_attachments) > 1) {
2644 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2648 iter = tny_list_create_iterator (selected_attachments);
2649 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2650 g_object_unref (iter);
2652 if (selected_attachments)
2653 g_object_unref (selected_attachments);
2658 g_object_ref (mime_part);
2661 if (tny_mime_part_is_purged (mime_part))
2664 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2665 gchar *filepath = NULL;
2666 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2667 gboolean show_error_banner = FALSE;
2668 TnyFsStream *temp_stream = NULL;
2669 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2672 if (temp_stream != NULL) {
2673 DecodeAsyncHelper *helper;
2675 /* Activate progress hint */
2676 set_progress_hint (window, TRUE);
2678 helper = g_slice_new0 (DecodeAsyncHelper);
2679 helper->self = g_object_ref (window);
2680 helper->file_path = g_strdup (filepath);
2682 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2683 on_decode_to_stream_async_handler,
2686 g_object_unref (temp_stream);
2687 /* NOTE: files in the temporary area will be automatically
2688 * cleaned after some time if they are no longer in use */
2691 const gchar *content_type;
2692 /* the file may already exist but it isn't writable,
2693 * let's try to open it anyway */
2694 content_type = tny_mime_part_get_content_type (mime_part);
2695 modest_platform_activate_file (filepath, content_type);
2697 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2698 show_error_banner = TRUE;
2703 if (show_error_banner)
2704 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2705 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2706 ModestWindowMgr *mgr;
2707 ModestWindow *msg_win = NULL;
2708 TnyMsg *current_msg;
2712 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2713 mgr = modest_runtime_get_window_mgr ();
2714 header = tny_msg_get_header (TNY_MSG (current_msg));
2715 found = modest_window_mgr_find_registered_message_uid (mgr,
2720 g_debug ("window for this body is already being created");
2723 /* it's not found, so create a new window for it */
2724 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2725 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2726 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2728 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2730 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part),
2731 account, mailbox, attachment_uid);
2733 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2734 modest_window_get_zoom (MODEST_WINDOW (window)));
2735 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2736 gtk_widget_show_all (GTK_WIDGET (msg_win));
2738 gtk_widget_destroy (GTK_WIDGET (msg_win));
2740 g_object_unref (current_msg);
2742 /* message attachment */
2743 TnyHeader *header = NULL;
2744 ModestWindowMgr *mgr;
2745 ModestWindow *msg_win = NULL;
2748 header = tny_msg_get_header (TNY_MSG (mime_part));
2749 mgr = modest_runtime_get_window_mgr ();
2750 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2753 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2754 * thus, we don't do anything */
2755 g_debug ("window for is already being created");
2757 /* it's not found, so create a new window for it */
2758 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2759 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2760 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2762 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2763 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account,
2764 mailbox, attachment_uid);
2765 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2766 modest_window_get_zoom (MODEST_WINDOW (window)));
2767 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2768 gtk_widget_show_all (GTK_WIDGET (msg_win));
2770 gtk_widget_destroy (GTK_WIDGET (msg_win));
2776 g_free (attachment_uid);
2778 g_object_unref (mime_part);
2790 GnomeVFSResult result;
2793 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2794 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2795 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2796 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
2799 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2803 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2804 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2805 g_free (pair->filename);
2806 g_object_unref (pair->part);
2807 g_slice_free (SaveMimePartPair, pair);
2809 g_list_free (info->pairs);
2812 g_slice_free (SaveMimePartInfo, info);
2817 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2819 /* This is a GDK lock because we are an idle callback and
2820 * hildon_banner_show_information is or does Gtk+ code */
2822 gdk_threads_enter (); /* CHECKED */
2823 if (info->result == GNOME_VFS_OK) {
2824 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2825 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
2826 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2827 modest_platform_information_banner (NULL, NULL, msg);
2830 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2832 save_mime_part_info_free (info, FALSE);
2833 gdk_threads_leave (); /* CHECKED */
2839 save_mime_part_to_file (SaveMimePartInfo *info)
2841 GnomeVFSHandle *handle;
2843 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2845 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2846 if (info->result == GNOME_VFS_OK) {
2847 GError *error = NULL;
2848 stream = tny_vfs_stream_new (handle);
2849 if (tny_mime_part_decode_to_stream (pair->part, stream, &error) < 0) {
2850 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
2852 if ((error->domain == TNY_ERROR_DOMAIN) &&
2853 (error->code == TNY_IO_ERROR_WRITE) &&
2854 (errno == ENOSPC)) {
2855 info->result = GNOME_VFS_ERROR_NO_SPACE;
2857 info->result = GNOME_VFS_ERROR_IO;
2860 g_object_unref (G_OBJECT (stream));
2862 g_warning ("Could not create save attachment %s: %s\n",
2863 pair->filename, gnome_vfs_result_to_string (info->result));
2866 /* Go on saving remaining files */
2867 info->pairs = g_list_remove_link (info->pairs, info->pairs);
2868 if (info->pairs != NULL) {
2869 save_mime_part_to_file (info);
2871 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2878 save_mime_parts_to_file_with_checks (GtkWindow *parent,
2879 SaveMimePartInfo *info)
2881 gboolean is_ok = TRUE;
2882 gint replaced_files = 0;
2883 const GList *files = info->pairs;
2884 const GList *iter, *to_replace = NULL;
2886 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2887 SaveMimePartPair *pair = iter->data;
2888 if (modest_utils_file_exists (pair->filename)) {
2890 if (replaced_files == 1)
2894 if (replaced_files) {
2897 if (replaced_files == 1) {
2898 SaveMimePartPair *pair = to_replace->data;
2899 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
2900 gchar *escaped_basename, *message;
2902 escaped_basename = g_uri_unescape_string (basename, NULL);
2903 message = g_strdup_printf ("%s\n%s",
2904 _FM("docm_nc_replace_file"),
2905 (escaped_basename) ? escaped_basename : "");
2906 response = modest_platform_run_confirmation_dialog (parent, message);
2908 g_free (escaped_basename);
2910 response = modest_platform_run_confirmation_dialog (parent,
2911 _FM("docm_nc_replace_multiple"));
2913 if (response != GTK_RESPONSE_OK)
2918 save_mime_part_info_free (info, TRUE);
2920 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2926 save_attachments_response (GtkDialog *dialog,
2930 TnyList *mime_parts;
2932 GList *files_to_save = NULL;
2933 gchar *current_folder;
2935 mime_parts = TNY_LIST (user_data);
2937 if (arg1 != GTK_RESPONSE_OK)
2940 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
2941 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2942 if (current_folder && current_folder != '\0') {
2944 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
2945 current_folder,&err);
2947 g_debug ("Error storing latest used folder: %s", err->message);
2951 g_free (current_folder);
2953 if (!modest_utils_folder_writable (chooser_uri)) {
2954 hildon_banner_show_information
2955 (NULL, NULL, _FM("sfil_ib_readonly_location"));
2959 iter = tny_list_create_iterator (mime_parts);
2960 while (!tny_iterator_is_done (iter)) {
2961 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2963 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
2964 !tny_mime_part_is_purged (mime_part) &&
2965 (tny_mime_part_get_filename (mime_part) != NULL)) {
2966 SaveMimePartPair *pair;
2968 pair = g_slice_new0 (SaveMimePartPair);
2970 if (tny_list_get_length (mime_parts) > 1) {
2972 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
2973 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
2976 pair->filename = g_strdup (chooser_uri);
2978 pair->part = mime_part;
2979 files_to_save = g_list_prepend (files_to_save, pair);
2981 tny_iterator_next (iter);
2983 g_object_unref (iter);
2985 g_free (chooser_uri);
2987 if (files_to_save != NULL) {
2988 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2989 info->pairs = files_to_save;
2990 info->result = TRUE;
2991 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
2995 /* Free and close the dialog */
2996 g_object_unref (mime_parts);
2997 gtk_widget_destroy (GTK_WIDGET (dialog));
3001 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3002 TnyList *mime_parts)
3004 ModestMsgViewWindowPrivate *priv;
3005 GtkWidget *save_dialog = NULL;
3006 gchar *conf_folder = NULL;
3007 gchar *filename = NULL;
3008 gchar *save_multiple_str = NULL;
3010 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3011 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3013 if (mime_parts == NULL) {
3014 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3015 * selection available */
3016 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3017 if (mime_parts && !modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, FALSE)) {
3018 g_object_unref (mime_parts);
3021 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3023 g_object_unref (mime_parts);
3029 g_object_ref (mime_parts);
3032 /* prepare dialog */
3033 if (tny_list_get_length (mime_parts) == 1) {
3035 /* only one attachment selected */
3036 iter = tny_list_create_iterator (mime_parts);
3037 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3038 g_object_unref (iter);
3039 if (!modest_tny_mime_part_is_msg (mime_part) &&
3040 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3041 !tny_mime_part_is_purged (mime_part)) {
3042 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3044 /* TODO: show any error? */
3045 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3046 g_object_unref (mime_parts);
3049 g_object_unref (mime_part);
3051 gint num = tny_list_get_length (mime_parts);
3052 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3053 "sfil_va_number_of_objects_attachment",
3054 "sfil_va_number_of_objects_attachments",
3058 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
3059 GTK_FILE_CHOOSER_ACTION_SAVE);
3062 conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3063 if (conf_folder && conf_folder[0] != '\0') {
3064 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3067 /* Set the default folder to images folder */
3068 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3069 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3070 g_free (docs_folder);
3072 g_free (conf_folder);
3076 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3081 /* if multiple, set multiple string */
3082 if (save_multiple_str) {
3083 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3084 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
3087 /* We must run this asynchronously, because the hildon dialog
3088 performs a gtk_dialog_run by itself which leads to gdk
3090 g_signal_connect (save_dialog, "response",
3091 G_CALLBACK (save_attachments_response), mime_parts);
3093 gtk_widget_show_all (save_dialog);
3097 show_remove_attachment_information (gpointer userdata)
3099 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3100 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3102 /* We're outside the main lock */
3103 gdk_threads_enter ();
3105 if (priv->remove_attachment_banner != NULL) {
3106 gtk_widget_destroy (priv->remove_attachment_banner);
3107 g_object_unref (priv->remove_attachment_banner);
3110 priv->remove_attachment_banner = g_object_ref (
3111 hildon_banner_show_animation (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3113 gdk_threads_leave ();
3119 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3121 ModestMsgViewWindowPrivate *priv;
3122 TnyList *mime_parts = NULL, *tmp;
3123 gchar *confirmation_message;
3129 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3130 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3132 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3133 * because we don't have selection
3135 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3137 /* Remove already purged messages from mime parts list. We use
3138 a copy of the list to remove items in the original one */
3139 tmp = tny_list_copy (mime_parts);
3140 iter = tny_list_create_iterator (tmp);
3141 while (!tny_iterator_is_done (iter)) {
3142 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3143 if (tny_mime_part_is_purged (part))
3144 tny_list_remove (mime_parts, (GObject *) part);
3146 g_object_unref (part);
3147 tny_iterator_next (iter);
3149 g_object_unref (tmp);
3150 g_object_unref (iter);
3152 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3153 tny_list_get_length (mime_parts) == 0) {
3154 g_object_unref (mime_parts);
3158 n_attachments = tny_list_get_length (mime_parts);
3159 if (n_attachments == 1) {
3163 iter = tny_list_create_iterator (mime_parts);
3164 part = (TnyMimePart *) tny_iterator_get_current (iter);
3165 g_object_unref (iter);
3166 if (modest_tny_mime_part_is_msg (part)) {
3168 header = tny_msg_get_header (TNY_MSG (part));
3169 filename = tny_header_dup_subject (header);
3170 g_object_unref (header);
3171 if (filename == NULL)
3172 filename = g_strdup (_("mail_va_no_subject"));
3174 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3176 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3178 g_object_unref (part);
3180 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3181 "mcen_nc_purge_files_text",
3182 n_attachments), n_attachments);
3184 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3185 confirmation_message);
3186 g_free (confirmation_message);
3188 if (response != GTK_RESPONSE_OK) {
3189 g_object_unref (mime_parts);
3193 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3195 iter = tny_list_create_iterator (mime_parts);
3196 while (!tny_iterator_is_done (iter)) {
3199 part = (TnyMimePart *) tny_iterator_get_current (iter);
3200 tny_mime_part_set_purged (TNY_MIME_PART (part));
3201 g_object_unref (part);
3202 tny_iterator_next (iter);
3204 g_object_unref (iter);
3206 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3207 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3208 tny_msg_rewrite_cache (msg);
3209 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3210 g_object_unref (msg);
3211 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3213 g_object_unref (mime_parts);
3215 if (priv->purge_timeout > 0) {
3216 g_source_remove (priv->purge_timeout);
3217 priv->purge_timeout = 0;
3220 if (priv->remove_attachment_banner) {
3221 gtk_widget_destroy (priv->remove_attachment_banner);
3222 g_object_unref (priv->remove_attachment_banner);
3223 priv->remove_attachment_banner = NULL;
3229 update_window_title (ModestMsgViewWindow *window)
3231 ModestMsgViewWindowPrivate *priv;
3233 TnyHeader *header = NULL;
3234 gchar *subject = NULL;
3236 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3238 /* Note that if the window is closed while we're retrieving
3239 the message, this widget could de deleted */
3240 if (!priv->msg_view)
3243 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3245 if (priv->other_body) {
3248 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3250 g_strstrip (description);
3251 subject = description;
3253 } else if (msg != NULL) {
3254 header = tny_msg_get_header (msg);
3255 subject = tny_header_dup_subject (header);
3256 g_object_unref (header);
3257 g_object_unref (msg);
3260 if ((subject == NULL)||(subject[0] == '\0')) {
3262 subject = g_strdup (_("mail_va_no_subject"));
3265 gtk_window_set_title (GTK_WINDOW (window), subject);
3270 on_move_focus (GtkWidget *widget,
3271 GtkDirectionType direction,
3274 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3278 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3280 GnomeVFSResult result;
3281 GnomeVFSHandle *handle = NULL;
3282 GnomeVFSFileInfo *info = NULL;
3285 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3286 if (result != GNOME_VFS_OK) {
3291 info = gnome_vfs_file_info_new ();
3292 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3293 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3294 /* We put a "safe" default size for going to cache */
3295 *expected_size = (300*1024);
3297 *expected_size = info->size;
3299 gnome_vfs_file_info_unref (info);
3301 stream = tny_vfs_stream_new (handle);
3310 TnyStream *output_stream;
3311 GtkWidget *msg_view;
3316 on_fetch_image_idle_refresh_view (gpointer userdata)
3319 FetchImageData *fidata = (FetchImageData *) userdata;
3321 gdk_threads_enter ();
3322 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3323 ModestMsgViewWindowPrivate *priv;
3325 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3326 priv->fetching_images--;
3327 gtk_widget_queue_draw (fidata->msg_view);
3328 update_progress_hint (MODEST_MSG_VIEW_WINDOW (fidata->window));
3330 gdk_threads_leave ();
3332 g_object_unref (fidata->msg_view);
3333 g_object_unref (fidata->window);
3334 g_slice_free (FetchImageData, fidata);
3339 on_fetch_image_thread (gpointer userdata)
3341 FetchImageData *fidata = (FetchImageData *) userdata;
3342 TnyStreamCache *cache;
3343 TnyStream *cache_stream;
3345 cache = modest_runtime_get_images_cache ();
3347 tny_stream_cache_get_stream (cache,
3349 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3350 (gpointer) fidata->uri);
3351 g_free (fidata->cache_id);
3352 g_free (fidata->uri);
3354 if (cache_stream != NULL) {
3357 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3360 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3361 if (G_UNLIKELY (nb_read < 0)) {
3363 } else if (G_LIKELY (nb_read > 0)) {
3364 gssize nb_written = 0;
3366 while (G_UNLIKELY (nb_written < nb_read)) {
3369 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3370 nb_read - nb_written);
3371 if (G_UNLIKELY (len < 0))
3377 tny_stream_close (cache_stream);
3378 g_object_unref (cache_stream);
3381 tny_stream_close (fidata->output_stream);
3382 g_object_unref (fidata->output_stream);
3384 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3390 on_fetch_image (ModestMsgView *msgview,
3393 ModestMsgViewWindow *window)
3395 const gchar *current_account;
3396 ModestMsgViewWindowPrivate *priv;
3397 FetchImageData *fidata;
3399 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3401 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3403 fidata = g_slice_new0 (FetchImageData);
3404 fidata->msg_view = g_object_ref (msgview);
3405 fidata->window = g_object_ref (window);
3406 fidata->uri = g_strdup (uri);
3407 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3408 fidata->output_stream = g_object_ref (stream);
3410 priv->fetching_images++;
3411 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3412 g_object_unref (fidata->output_stream);
3413 g_free (fidata->cache_id);
3414 g_free (fidata->uri);
3415 g_object_unref (fidata->msg_view);
3416 g_slice_free (FetchImageData, fidata);
3417 tny_stream_close (stream);
3418 priv->fetching_images--;
3419 update_progress_hint (window);
3422 update_progress_hint (window);
3428 setup_menu (ModestMsgViewWindow *self)
3430 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3432 /* Settings menu buttons */
3433 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_replytoall"), NULL,
3434 APP_MENU_CALLBACK (modest_ui_actions_on_reply_all),
3435 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3436 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_forward"), "<Control>d",
3437 APP_MENU_CALLBACK (modest_ui_actions_on_forward),
3438 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3440 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3441 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3442 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3443 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3444 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3445 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3447 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3448 APP_MENU_CALLBACK (modest_ui_actions_save_attachments),
3449 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3450 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3451 APP_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3452 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3454 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3455 APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3456 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3457 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3458 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3459 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3461 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mail_bd_external_images"), NULL,
3462 APP_MENU_CALLBACK (modest_ui_actions_on_fetch_images),
3463 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_fetch_images));
3464 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3465 APP_MENU_CALLBACK (modest_ui_actions_on_details),
3466 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3470 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3472 ModestMsgViewWindowPrivate *priv;
3473 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3474 GSList *recipients = NULL;
3476 gboolean contacts_to_add = FALSE;
3478 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3482 header = modest_msg_view_window_get_header (self);
3485 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3486 g_object_unref (header);
3488 recipients = modest_tny_msg_get_all_recipients_list (msg);
3489 g_object_unref (msg);
3492 if (recipients != NULL) {
3493 GtkWidget *picker_dialog;
3494 GtkWidget *selector;
3496 gchar *selected = NULL;
3498 selector = hildon_touch_selector_new_text ();
3499 g_object_ref (selector);
3501 for (node = recipients; node != NULL; node = g_slist_next (node)) {
3502 if (!modest_address_book_has_address ((const gchar *) node->data)) {
3503 hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector),
3504 (const gchar *) node->data);
3505 contacts_to_add = TRUE;
3509 if (contacts_to_add) {
3512 picker_dialog = hildon_picker_dialog_new (GTK_WINDOW (self));
3513 gtk_window_set_title (GTK_WINDOW (picker_dialog), _("mcen_me_viewer_addtocontacts"));
3515 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (picker_dialog),
3516 HILDON_TOUCH_SELECTOR (selector));
3518 picker_result = gtk_dialog_run (GTK_DIALOG (picker_dialog));
3520 if (picker_result == GTK_RESPONSE_OK) {
3521 selected = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
3523 gtk_widget_destroy (picker_dialog);
3526 modest_address_book_add_address (selected);
3531 g_object_unref (selector);
3536 if (recipients) {g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);}
3540 _modest_msg_view_window_map_event (GtkWidget *widget,
3544 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
3546 update_progress_hint (self);
3552 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
3554 ModestMsgViewWindowPrivate *priv;
3555 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3557 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
3561 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
3563 ModestMsgViewWindowPrivate *priv;
3564 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3566 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
3568 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
3572 modest_msg_view_window_reload (ModestMsgViewWindow *self)
3574 ModestMsgViewWindowPrivate *priv;
3577 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
3579 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3580 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
3582 if (!message_reader (self, priv, header, NULL, NULL, priv->row_reference)) {
3583 g_warning ("Shouldn't happen, trying to reload a message failed");
3586 g_object_unref (header);
3590 update_branding (ModestMsgViewWindow *self)
3592 const gchar *account;
3593 const gchar *mailbox;
3594 ModestAccountMgr *mgr;
3595 ModestProtocol *protocol = NULL;
3596 gchar *service_name = NULL;
3597 const GdkPixbuf *service_icon = NULL;
3598 ModestMsgViewWindowPrivate *priv;
3600 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3602 account = modest_window_get_active_account (MODEST_WINDOW (self));
3603 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
3605 mgr = modest_runtime_get_account_mgr ();
3607 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3608 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3609 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
3611 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
3612 account, mailbox, MODEST_ICON_SIZE_SMALL);
3616 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
3617 g_free (service_name);