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 = tny_store_account_find_folder (TNY_STORE_ACCOUNT (account), msg_uid, NULL);
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_branding (MODEST_MSG_VIEW_WINDOW (window));
986 g_object_unref (msg);
988 message_reader (window, priv, NULL, msg_uid, folder, NULL);
991 g_object_unref (folder);
996 /* Check dimming rules */
997 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
998 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
999 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1001 return MODEST_WINDOW(window);
1005 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
1006 const gchar *modest_account_name,
1007 const gchar *mailbox,
1008 const gchar *msg_uid,
1009 GtkTreeRowReference *row_reference)
1011 ModestMsgViewWindow *window = NULL;
1012 ModestMsgViewWindowPrivate *priv = NULL;
1013 TnyFolder *header_folder = NULL;
1014 ModestWindowMgr *mgr = NULL;
1018 mgr = modest_runtime_get_window_mgr ();
1019 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1020 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1022 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1024 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1026 /* Remember the message list's TreeModel so we can detect changes
1027 * and change the list selection when necessary: */
1029 if (header_view != NULL){
1030 header_folder = modest_header_view_get_folder(header_view);
1031 /* This could happen if the header folder was
1032 unseleted before opening this msg window (for
1033 example if the user selects an account in the
1034 folder view of the main window */
1035 if (header_folder) {
1036 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
1037 TNY_FOLDER_TYPE_OUTBOX);
1038 priv->header_folder_id = tny_folder_get_id(header_folder);
1039 g_object_unref(header_folder);
1043 /* Setup row references and connect signals */
1044 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
1045 g_object_ref (priv->header_model);
1047 if (row_reference) {
1048 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1049 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
1050 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
1052 priv->row_reference = NULL;
1053 priv->next_row_reference = NULL;
1056 /* Connect signals */
1057 priv->row_changed_handler =
1058 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
1059 G_CALLBACK(modest_msg_view_window_on_row_changed),
1061 priv->row_deleted_handler =
1062 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
1063 G_CALLBACK(modest_msg_view_window_on_row_deleted),
1065 priv->row_inserted_handler =
1066 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
1067 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1069 priv->rows_reordered_handler =
1070 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
1071 G_CALLBACK(modest_msg_view_window_on_row_reordered),
1074 if (header_view != NULL){
1075 modest_header_view_add_observer(header_view,
1076 MODEST_HEADER_VIEW_OBSERVER(window));
1079 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
1080 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1082 path = gtk_tree_row_reference_get_path (row_reference);
1083 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1085 gtk_tree_model_get (priv->header_model, &iter,
1086 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1088 message_reader (window, priv, header, NULL, NULL, row_reference);
1089 g_object_unref (header);
1091 gtk_tree_path_free (path);
1093 /* Check dimming rules */
1094 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1095 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1096 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1098 return MODEST_WINDOW(window);
1102 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1103 const gchar *modest_account_name,
1104 const gchar *mailbox,
1105 const gchar *msg_uid)
1107 ModestMsgViewWindow *window = NULL;
1108 ModestMsgViewWindowPrivate *priv = NULL;
1109 ModestWindowMgr *mgr = NULL;
1111 mgr = modest_runtime_get_window_mgr ();
1112 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1113 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1114 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1116 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1118 /* Remember that this is a search result,
1119 * so we can disable some UI appropriately: */
1120 priv->is_search_result = TRUE;
1122 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1123 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1125 update_window_title (window);
1126 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1127 modest_msg_view_window_update_priority (window);
1129 /* Check dimming rules */
1130 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1131 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1132 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1134 return MODEST_WINDOW(window);
1138 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1140 ModestMsgViewWindowPrivate *priv = NULL;
1142 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1143 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1145 return (priv->other_body != NULL);
1149 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1150 TnyMimePart *other_body,
1151 const gchar *modest_account_name,
1152 const gchar *mailbox,
1153 const gchar *msg_uid)
1155 GObject *obj = NULL;
1156 ModestMsgViewWindowPrivate *priv;
1157 ModestWindowMgr *mgr = NULL;
1159 g_return_val_if_fail (msg, NULL);
1160 mgr = modest_runtime_get_window_mgr ();
1161 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1162 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1163 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1164 modest_account_name, mailbox, msg_uid);
1167 priv->other_body = g_object_ref (other_body);
1168 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1170 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1172 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1173 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1175 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1177 /* Check dimming rules */
1178 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1179 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1180 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1182 return MODEST_WINDOW(obj);
1186 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1187 const gchar *modest_account_name,
1188 const gchar *mailbox,
1189 const gchar *msg_uid)
1191 return modest_msg_view_window_new_with_other_body (msg, NULL, modest_account_name, mailbox, msg_uid);
1195 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1198 ModestMsgViewWindow *window)
1200 check_dimming_rules_after_change (window);
1204 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1206 ModestMsgViewWindow *window)
1208 check_dimming_rules_after_change (window);
1210 /* The window could have dissapeared */
1213 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1215 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1216 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1220 /* On insertions we check if the folder still has the message we are
1221 * showing or do not. If do not, we do nothing. Which means we are still
1222 * not attached to any header folder and thus next/prev buttons are
1223 * still dimmed. Once the message that is shown by msg-view is found, the
1224 * new model of header-view will be attached and the references will be set.
1225 * On each further insertions dimming rules will be checked. However
1226 * this requires extra CPU time at least works.
1227 * (An message might be deleted from TnyFolder and thus will not be
1228 * inserted into the model again for example if it is removed by the
1229 * imap server and the header view is refreshed.)
1232 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1233 GtkTreePath *tree_path,
1234 GtkTreeIter *tree_iter,
1235 ModestMsgViewWindow *window)
1237 ModestMsgViewWindowPrivate *priv = NULL;
1238 TnyHeader *header = NULL;
1240 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1241 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1243 g_assert (model == priv->header_model);
1245 /* Check if the newly inserted message is the same we are actually
1246 * showing. IF not, we should remain detached from the header model
1247 * and thus prev and next toolbar buttons should remain dimmed. */
1248 gtk_tree_model_get (model, tree_iter,
1249 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1252 if (TNY_IS_HEADER (header)) {
1255 uid = modest_tny_folder_get_header_unique_id (header);
1256 if (!g_str_equal(priv->msg_uid, uid)) {
1257 check_dimming_rules_after_change (window);
1259 g_object_unref (G_OBJECT(header));
1263 g_object_unref(G_OBJECT(header));
1266 if (priv->row_reference) {
1267 gtk_tree_row_reference_free (priv->row_reference);
1270 /* Setup row_reference for the actual msg. */
1271 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1272 if (priv->row_reference == NULL) {
1273 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1277 /* Now set up next_row_reference. */
1278 if (priv->next_row_reference) {
1279 gtk_tree_row_reference_free (priv->next_row_reference);
1282 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1283 select_next_valid_row (priv->header_model,
1284 &(priv->next_row_reference), FALSE, priv->is_outbox);
1286 /* Connect the remaining callbacks to become able to detect
1287 * changes in header-view. */
1288 priv->row_changed_handler =
1289 g_signal_connect (priv->header_model, "row-changed",
1290 G_CALLBACK (modest_msg_view_window_on_row_changed),
1292 priv->row_deleted_handler =
1293 g_signal_connect (priv->header_model, "row-deleted",
1294 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1296 priv->rows_reordered_handler =
1297 g_signal_connect (priv->header_model, "rows-reordered",
1298 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1301 check_dimming_rules_after_change (window);
1305 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1309 ModestMsgViewWindow *window)
1311 ModestMsgViewWindowPrivate *priv = NULL;
1312 gboolean already_changed = FALSE;
1314 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1316 /* If the current row was reordered select the proper next
1317 valid row. The same if the next row reference changes */
1318 if (priv->row_reference &&
1319 gtk_tree_row_reference_valid (priv->row_reference)) {
1321 path = gtk_tree_row_reference_get_path (priv->row_reference);
1322 if (gtk_tree_path_compare (path, arg1) == 0) {
1323 if (priv->next_row_reference) {
1324 gtk_tree_row_reference_free (priv->next_row_reference);
1326 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1327 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1328 already_changed = TRUE;
1330 gtk_tree_path_free (path);
1332 if (!already_changed &&
1333 priv->next_row_reference &&
1334 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1336 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1337 if (gtk_tree_path_compare (path, arg1) == 0) {
1338 if (priv->next_row_reference) {
1339 gtk_tree_row_reference_free (priv->next_row_reference);
1341 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1342 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1344 gtk_tree_path_free (path);
1346 check_dimming_rules_after_change (window);
1349 /* The modest_msg_view_window_update_model_replaced implements update
1350 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1351 * actually belongs to the header-view is the same as the TnyFolder of
1352 * the message of msg-view or not. If they are different, there is
1353 * nothing to do. If they are the same, then the model has replaced and
1354 * the reference in msg-view shall be replaced from the old model to
1355 * the new model. In this case the view will be detached from it's
1356 * header folder. From this point the next/prev buttons are dimmed.
1359 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1360 GtkTreeModel *model,
1361 const gchar *tny_folder_id)
1363 ModestMsgViewWindowPrivate *priv = NULL;
1364 ModestMsgViewWindow *window = NULL;
1366 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1367 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1369 window = MODEST_MSG_VIEW_WINDOW(observer);
1370 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1372 /* If there is an other folder in the header-view then we do
1373 * not care about it's model (msg list). Else if the
1374 * header-view shows the folder the msg shown by us is in, we
1375 * shall replace our model reference and make some check. */
1376 if(model == NULL || tny_folder_id == NULL ||
1377 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1380 /* Model is changed(replaced), so we should forget the old
1381 * one. Because there might be other references and there
1382 * might be some change on the model even if we unreferenced
1383 * it, we need to disconnect our signals here. */
1384 if (priv->header_model) {
1385 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1386 priv->row_changed_handler))
1387 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1388 priv->row_changed_handler);
1389 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1390 priv->row_deleted_handler))
1391 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1392 priv->row_deleted_handler);
1393 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1394 priv->row_inserted_handler))
1395 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1396 priv->row_inserted_handler);
1397 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1398 priv->rows_reordered_handler))
1399 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1400 priv->rows_reordered_handler);
1403 if (priv->row_reference)
1404 gtk_tree_row_reference_free (priv->row_reference);
1405 if (priv->next_row_reference)
1406 gtk_tree_row_reference_free (priv->next_row_reference);
1407 g_object_unref(priv->header_model);
1410 priv->row_changed_handler = 0;
1411 priv->row_deleted_handler = 0;
1412 priv->row_inserted_handler = 0;
1413 priv->rows_reordered_handler = 0;
1414 priv->next_row_reference = NULL;
1415 priv->row_reference = NULL;
1416 priv->header_model = NULL;
1419 priv->header_model = g_object_ref (model);
1421 /* Also we must connect to the new model for row insertions.
1422 * Only for insertions now. We will need other ones only after
1423 * the msg is show by msg-view is added to the new model. */
1424 priv->row_inserted_handler =
1425 g_signal_connect (priv->header_model, "row-inserted",
1426 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1429 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1430 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1434 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1436 ModestMsgViewWindowPrivate *priv= NULL;
1438 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1439 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1441 return priv->progress_hint;
1445 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1447 ModestMsgViewWindowPrivate *priv= NULL;
1449 TnyHeader *header = NULL;
1450 GtkTreePath *path = NULL;
1453 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1454 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1456 /* If the message was not obtained from a treemodel,
1457 * for instance if it was opened directly by the search UI:
1459 if (priv->header_model == NULL ||
1460 priv->row_reference == NULL ||
1461 !gtk_tree_row_reference_valid (priv->row_reference)) {
1462 msg = modest_msg_view_window_get_message (self);
1464 header = tny_msg_get_header (msg);
1465 g_object_unref (msg);
1470 /* Get iter of the currently selected message in the header view: */
1471 path = gtk_tree_row_reference_get_path (priv->row_reference);
1472 g_return_val_if_fail (path != NULL, NULL);
1473 gtk_tree_model_get_iter (priv->header_model,
1477 /* Get current message header */
1478 gtk_tree_model_get (priv->header_model, &iter,
1479 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1482 gtk_tree_path_free (path);
1487 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1489 ModestMsgViewWindowPrivate *priv;
1491 g_return_val_if_fail (self, NULL);
1493 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1495 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1499 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1501 ModestMsgViewWindowPrivate *priv;
1503 g_return_val_if_fail (self, NULL);
1505 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1507 return (const gchar*) priv->msg_uid;
1511 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1514 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1515 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1516 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1520 is_active = gtk_toggle_action_get_active (toggle);
1523 gtk_widget_show (priv->find_toolbar);
1524 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1526 gtk_widget_hide (priv->find_toolbar);
1527 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1530 /* update the toggle buttons status */
1531 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1533 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1538 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1539 ModestMsgViewWindow *obj)
1541 GtkToggleAction *toggle;
1542 ModestWindowPrivate *parent_priv;
1543 ModestMsgViewWindowPrivate *priv;
1545 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1546 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1548 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1549 gtk_toggle_action_set_active (toggle, FALSE);
1550 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1554 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1555 ModestMsgViewWindow *obj)
1557 gchar *current_search;
1558 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1560 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1561 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1565 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1567 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1568 g_free (current_search);
1569 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
1573 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1575 g_free (priv->last_search);
1576 priv->last_search = g_strdup (current_search);
1577 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1580 hildon_banner_show_information (NULL, NULL,
1581 _HL("ckct_ib_find_no_matches"));
1582 g_free (priv->last_search);
1583 priv->last_search = NULL;
1585 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1588 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1589 hildon_banner_show_information (NULL, NULL,
1590 _HL("ckct_ib_find_search_complete"));
1591 g_free (priv->last_search);
1592 priv->last_search = NULL;
1594 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1598 g_free (current_search);
1603 modest_msg_view_window_set_zoom (ModestWindow *window,
1606 ModestMsgViewWindowPrivate *priv;
1607 ModestWindowPrivate *parent_priv;
1609 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1611 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1612 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1613 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1618 modest_msg_view_window_get_zoom (ModestWindow *window)
1620 ModestMsgViewWindowPrivate *priv;
1622 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1624 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1625 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1629 modest_msg_view_window_zoom_plus (ModestWindow *window)
1632 ModestMsgViewWindowPrivate *priv;
1636 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1637 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1639 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1641 if (zoom_level >= 2.0) {
1642 hildon_banner_show_information (NULL, NULL,
1643 _CS("ckct_ib_max_zoom_level_reached"));
1645 } else if (zoom_level >= 1.5) {
1647 } else if (zoom_level >= 1.2) {
1649 } else if (zoom_level >= 1.0) {
1651 } else if (zoom_level >= 0.8) {
1653 } else if (zoom_level >= 0.5) {
1659 /* set zoom level */
1660 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1661 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1662 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1663 g_free (banner_text);
1664 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1670 modest_msg_view_window_zoom_minus (ModestWindow *window)
1673 ModestMsgViewWindowPrivate *priv;
1677 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1678 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1680 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1682 if (zoom_level <= 0.5) {
1683 hildon_banner_show_information (NULL, NULL,
1684 _CS("ckct_ib_min_zoom_level_reached"));
1686 } else if (zoom_level <= 0.8) {
1688 } else if (zoom_level <= 1.0) {
1690 } else if (zoom_level <= 1.2) {
1692 } else if (zoom_level <= 1.5) {
1694 } else if (zoom_level <= 2.0) {
1700 /* set zoom level */
1701 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1702 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1703 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1704 g_free (banner_text);
1705 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1712 modest_msg_view_window_key_event (GtkWidget *window,
1718 focus = gtk_window_get_focus (GTK_WINDOW (window));
1720 /* for the find toolbar case */
1721 if (focus && GTK_IS_ENTRY (focus)) {
1722 if (event->keyval == GDK_BackSpace) {
1724 copy = gdk_event_copy ((GdkEvent *) event);
1725 gtk_widget_event (focus, copy);
1726 gdk_event_free (copy);
1731 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1732 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1733 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1734 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1735 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1736 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1737 /* ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); */
1738 /* gboolean return_value; */
1740 if (event->type == GDK_KEY_PRESS) {
1741 GtkScrollType scroll_type;
1743 switch (event->keyval) {
1746 scroll_type = GTK_SCROLL_STEP_UP; break;
1749 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1751 case GDK_KP_Page_Up:
1752 scroll_type = GTK_SCROLL_PAGE_UP; break;
1754 case GDK_KP_Page_Down:
1755 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1758 scroll_type = GTK_SCROLL_START; break;
1761 scroll_type = GTK_SCROLL_END; break;
1762 default: scroll_type = GTK_SCROLL_NONE;
1765 /* g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", */
1766 /* scroll_type, FALSE, &return_value); */
1777 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1780 ModestMsgViewWindowPrivate *priv;
1781 GtkTreeIter tmp_iter;
1782 gboolean is_last_selected;
1784 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1785 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1787 /*if no model (so no rows at all), then virtually we are the last*/
1788 if (!priv->header_model || !priv->row_reference)
1791 if (!gtk_tree_row_reference_valid (priv->row_reference))
1794 path = gtk_tree_row_reference_get_path (priv->row_reference);
1798 is_last_selected = TRUE;
1799 while (is_last_selected) {
1801 gtk_tree_path_next (path);
1802 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1804 gtk_tree_model_get (priv->header_model, &tmp_iter,
1805 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1808 if (msg_is_visible (header, priv->is_outbox))
1809 is_last_selected = FALSE;
1810 g_object_unref(G_OBJECT(header));
1813 gtk_tree_path_free (path);
1814 return is_last_selected;
1818 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1820 ModestMsgViewWindowPrivate *priv;
1822 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1823 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1825 return priv->header_model != NULL;
1829 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1831 ModestMsgViewWindowPrivate *priv;
1833 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1834 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1836 return priv->is_search_result;
1840 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1842 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1844 if (!check_outbox) {
1847 ModestTnySendQueueStatus status;
1848 status = modest_tny_all_send_queues_get_msg_status (header);
1849 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1850 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1855 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1858 ModestMsgViewWindowPrivate *priv;
1859 gboolean is_first_selected;
1860 GtkTreeIter tmp_iter;
1862 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1863 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1865 /*if no model (so no rows at all), then virtually we are the first*/
1866 if (!priv->header_model || !priv->row_reference)
1869 if (!gtk_tree_row_reference_valid (priv->row_reference))
1872 path = gtk_tree_row_reference_get_path (priv->row_reference);
1876 is_first_selected = TRUE;
1877 while (is_first_selected) {
1879 if(!gtk_tree_path_prev (path))
1881 /* Here the 'if' is needless for logic, but let make sure
1882 * iter is valid for gtk_tree_model_get. */
1883 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1885 gtk_tree_model_get (priv->header_model, &tmp_iter,
1886 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1889 if (msg_is_visible (header, priv->is_outbox))
1890 is_first_selected = FALSE;
1891 g_object_unref(G_OBJECT(header));
1894 gtk_tree_path_free (path);
1895 return is_first_selected;
1902 GtkTreeRowReference *row_reference;
1906 message_reader_performer (gboolean canceled,
1908 GtkWindow *parent_window,
1909 TnyAccount *account,
1912 ModestMailOperation *mail_op = NULL;
1913 MsgReaderInfo *info;
1915 info = (MsgReaderInfo *) user_data;
1916 if (canceled || err) {
1917 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1921 /* Register the header - it'll be unregistered in the callback */
1922 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1924 /* New mail operation */
1925 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1926 modest_ui_actions_disk_operations_error_handler,
1929 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1931 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1933 modest_mail_operation_find_msg (mail_op, info->folder, info->msg_uid, TRUE, view_msg_cb, NULL);
1934 g_object_unref (mail_op);
1936 /* Update dimming rules */
1937 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1938 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1941 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1942 g_free (info->msg_uid);
1944 g_object_unref (info->folder);
1946 g_object_unref (info->header);
1947 g_slice_free (MsgReaderInfo, info);
1952 * Reads the message whose summary item is @header. It takes care of
1953 * several things, among others:
1955 * If the message was not previously downloaded then ask the user
1956 * before downloading. If there is no connection launch the connection
1957 * dialog. Update toolbar dimming rules.
1959 * Returns: TRUE if the mail operation was started, otherwise if the
1960 * user do not want to download the message, or if the user do not
1961 * want to connect, then the operation is not issued
1964 message_reader (ModestMsgViewWindow *window,
1965 ModestMsgViewWindowPrivate *priv,
1967 const gchar *msg_uid,
1969 GtkTreeRowReference *row_reference)
1971 ModestWindowMgr *mgr;
1972 TnyAccount *account;
1973 MsgReaderInfo *info;
1975 /* We set the header from model while we're loading */
1976 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
1977 gtk_window_set_title (GTK_WINDOW (window), _CS("ckdg_pb_updating"));
1979 mgr = modest_runtime_get_window_mgr ();
1980 /* Msg download completed */
1981 if (!header || !(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1983 /* Ask the user if he wants to download the message if
1985 if (!tny_device_is_online (modest_runtime_get_device())) {
1986 GtkResponseType response;
1988 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1989 _("mcen_nc_get_msg"));
1990 if (response == GTK_RESPONSE_CANCEL) {
1991 update_window_title (window);
1996 folder = tny_header_get_folder (header);
1998 g_object_ref (folder);
2000 info = g_slice_new (MsgReaderInfo);
2001 info->msg_uid = g_strdup (msg_uid);
2003 info->header = g_object_ref (header);
2005 info->header = NULL;
2007 info->folder = g_object_ref (folder);
2009 info->folder = NULL;
2010 if (row_reference) {
2011 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2013 info->row_reference = NULL;
2016 /* Offer the connection dialog if necessary */
2017 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
2019 TNY_FOLDER_STORE (folder),
2020 message_reader_performer,
2022 g_object_unref (folder);
2028 folder = tny_header_get_folder (header);
2030 g_object_ref (folder);
2032 account = tny_folder_get_account (folder);
2033 info = g_slice_new (MsgReaderInfo);
2034 info->msg_uid = g_strdup (msg_uid);
2036 info->folder = g_object_ref (folder);
2038 info->folder = NULL;
2040 info->header = g_object_ref (header);
2042 info->header = NULL;
2044 info->row_reference = gtk_tree_row_reference_copy (row_reference);
2046 info->row_reference = NULL;
2048 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
2049 g_object_unref (account);
2050 g_object_unref (folder);
2056 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
2058 ModestMsgViewWindowPrivate *priv;
2059 GtkTreePath *path= NULL;
2060 GtkTreeIter tmp_iter;
2062 gboolean retval = TRUE;
2063 GtkTreeRowReference *row_reference = NULL;
2065 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2066 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2068 if (!priv->row_reference)
2071 /* Update the next row reference if it's not valid. This could
2072 happen if for example the header which it was pointing to,
2073 was deleted. The best place to do it is in the row-deleted
2074 handler but the tinymail model do not work like the glib
2075 tree models and reports the deletion when the row is still
2077 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
2078 if (gtk_tree_row_reference_valid (priv->row_reference)) {
2079 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2080 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
2083 if (priv->next_row_reference)
2084 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
2088 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
2090 gtk_tree_model_get_iter (priv->header_model,
2093 gtk_tree_path_free (path);
2095 gtk_tree_model_get (priv->header_model, &tmp_iter,
2096 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2099 /* Read the message & show it */
2100 if (!message_reader (window, priv, header, NULL, NULL, row_reference)) {
2103 gtk_tree_row_reference_free (row_reference);
2106 g_object_unref (header);
2112 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
2114 ModestMsgViewWindowPrivate *priv = NULL;
2116 gboolean finished = FALSE;
2117 gboolean retval = FALSE;
2119 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
2120 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2122 /* Return inmediatly if there is no header model */
2123 if (!priv->header_model || !priv->row_reference)
2126 path = gtk_tree_row_reference_get_path (priv->row_reference);
2127 while (!finished && gtk_tree_path_prev (path)) {
2131 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2132 gtk_tree_model_get (priv->header_model, &iter,
2133 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2137 if (msg_is_visible (header, priv->is_outbox)) {
2138 GtkTreeRowReference *row_reference;
2139 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2140 /* Read the message & show it */
2141 retval = message_reader (window, priv, header, NULL, NULL, row_reference);
2142 gtk_tree_row_reference_free (row_reference);
2146 g_object_unref (header);
2150 gtk_tree_path_free (path);
2155 view_msg_cb (ModestMailOperation *mail_op,
2162 ModestMsgViewWindow *self = NULL;
2163 ModestMsgViewWindowPrivate *priv = NULL;
2164 GtkTreeRowReference *row_reference = NULL;
2166 /* Unregister the header (it was registered before creating the mail operation) */
2167 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2169 row_reference = (GtkTreeRowReference *) user_data;
2172 gtk_tree_row_reference_free (row_reference);
2173 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2175 /* Restore window title */
2176 update_window_title (self);
2177 g_object_unref (self);
2182 /* If there was any error */
2183 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2185 gtk_tree_row_reference_free (row_reference);
2186 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2188 /* Restore window title */
2189 update_window_title (self);
2190 g_object_unref (self);
2195 /* Get the window */
2196 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2197 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2198 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2200 /* Update the row reference */
2201 if (priv->row_reference != NULL) {
2202 gtk_tree_row_reference_free (priv->row_reference);
2203 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
2204 if (priv->next_row_reference != NULL) {
2205 gtk_tree_row_reference_free (priv->next_row_reference);
2207 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2208 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2211 /* Mark header as read */
2212 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2213 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2215 /* Set new message */
2216 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2217 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2218 modest_msg_view_window_update_priority (self);
2219 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2220 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2221 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2224 /* Set the new message uid of the window */
2225 if (priv->msg_uid) {
2226 g_free (priv->msg_uid);
2227 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2230 /* Notify the observers */
2231 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2232 0, priv->header_model, priv->row_reference);
2235 g_object_unref (self);
2237 gtk_tree_row_reference_free (row_reference);
2241 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2243 ModestMsgViewWindowPrivate *priv;
2245 TnyFolderType folder_type;
2247 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2249 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2251 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2255 folder = tny_msg_get_folder (msg);
2257 folder_type = modest_tny_folder_guess_folder_type (folder);
2258 g_object_unref (folder);
2260 g_object_unref (msg);
2268 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2270 ModestMsgViewWindowPrivate *priv;
2271 TnyHeader *header = NULL;
2272 TnyHeaderFlags flags = 0;
2274 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2276 if (priv->header_model && priv->row_reference) {
2278 GtkTreePath *path = NULL;
2280 path = gtk_tree_row_reference_get_path (priv->row_reference);
2281 g_return_if_fail (path != NULL);
2282 gtk_tree_model_get_iter (priv->header_model,
2284 gtk_tree_row_reference_get_path (priv->row_reference));
2286 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2288 gtk_tree_path_free (path);
2291 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2293 header = tny_msg_get_header (msg);
2294 g_object_unref (msg);
2299 flags = tny_header_get_flags (header);
2300 g_object_unref(G_OBJECT(header));
2303 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2308 toolbar_resize (ModestMsgViewWindow *self)
2310 ModestMsgViewWindowPrivate *priv = NULL;
2311 ModestWindowPrivate *parent_priv = NULL;
2313 gint static_button_size;
2314 ModestWindowMgr *mgr;
2316 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2317 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2318 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2320 mgr = modest_runtime_get_window_mgr ();
2321 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2323 if (parent_priv->toolbar) {
2324 /* left size buttons */
2325 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2326 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2327 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2328 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2329 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
2330 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2331 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2332 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2333 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2334 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2335 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2336 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2337 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
2338 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2339 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2340 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2342 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2343 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2344 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2345 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2350 modest_msg_view_window_show_toolbar (ModestWindow *self,
2351 gboolean show_toolbar)
2353 ModestMsgViewWindowPrivate *priv = NULL;
2354 ModestWindowPrivate *parent_priv;
2356 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2357 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2359 /* Set optimized view status */
2360 priv->optimized_view = !show_toolbar;
2362 if (!parent_priv->toolbar) {
2363 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2365 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2366 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2368 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2369 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2370 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2373 hildon_window_add_toolbar (HILDON_WINDOW (self),
2374 GTK_TOOLBAR (parent_priv->toolbar));
2379 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2380 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2381 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2383 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2384 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2385 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2387 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2390 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2391 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2396 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2398 ModestMsgViewWindow *window)
2400 if (!GTK_WIDGET_VISIBLE (window))
2403 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2407 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2409 ModestMsgViewWindowPrivate *priv;
2411 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2412 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2414 return priv->progress_hint;
2418 observers_empty (ModestMsgViewWindow *self)
2421 ModestMsgViewWindowPrivate *priv;
2422 gboolean is_empty = TRUE;
2423 guint pending_ops = 0;
2425 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2426 tmp = priv->progress_widgets;
2428 /* Check all observers */
2429 while (tmp && is_empty) {
2430 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2431 is_empty = pending_ops == 0;
2433 tmp = g_slist_next(tmp);
2440 on_account_removed (TnyAccountStore *account_store,
2441 TnyAccount *account,
2444 /* Do nothing if it's a transport account, because we only
2445 show the messages of a store account */
2446 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2447 const gchar *parent_acc = NULL;
2448 const gchar *our_acc = NULL;
2450 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2451 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2453 /* Close this window if I'm showing a message of the removed account */
2454 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2455 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2460 on_mail_operation_started (ModestMailOperation *mail_op,
2463 ModestMsgViewWindow *self;
2464 ModestMailOperationTypeOperation op_type;
2466 ModestMsgViewWindowPrivate *priv;
2467 GObject *source = NULL;
2469 self = MODEST_MSG_VIEW_WINDOW (user_data);
2470 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2471 op_type = modest_mail_operation_get_type_operation (mail_op);
2472 tmp = priv->progress_widgets;
2473 source = modest_mail_operation_get_source(mail_op);
2474 if (G_OBJECT (self) == source) {
2475 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2476 set_toolbar_transfer_mode(self);
2478 modest_progress_object_add_operation (
2479 MODEST_PROGRESS_OBJECT (tmp->data),
2481 tmp = g_slist_next (tmp);
2485 g_object_unref (source);
2489 on_mail_operation_finished (ModestMailOperation *mail_op,
2492 ModestMsgViewWindow *self;
2493 ModestMailOperationTypeOperation op_type;
2495 ModestMsgViewWindowPrivate *priv;
2497 self = MODEST_MSG_VIEW_WINDOW (user_data);
2498 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2499 op_type = modest_mail_operation_get_type_operation (mail_op);
2500 tmp = priv->progress_widgets;
2502 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2504 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2506 tmp = g_slist_next (tmp);
2509 /* If no more operations are being observed, NORMAL mode is enabled again */
2510 if (observers_empty (self)) {
2511 set_progress_hint (self, FALSE);
2515 /* Update dimming rules. We have to do this right here
2516 and not in view_msg_cb because at that point the
2517 transfer mode is still enabled so the dimming rule
2518 won't let the user delete the message that has been
2519 readed for example */
2520 check_dimming_rules_after_change (self);
2525 on_queue_changed (ModestMailOperationQueue *queue,
2526 ModestMailOperation *mail_op,
2527 ModestMailOperationQueueNotification type,
2528 ModestMsgViewWindow *self)
2530 ModestMsgViewWindowPrivate *priv;
2532 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2534 /* If this operations was created by another window, do nothing */
2535 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2538 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2539 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2541 "operation-started",
2542 G_CALLBACK (on_mail_operation_started),
2544 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2546 "operation-finished",
2547 G_CALLBACK (on_mail_operation_finished),
2549 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2550 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2552 "operation-started");
2553 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2555 "operation-finished");
2560 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2562 ModestMsgViewWindowPrivate *priv;
2563 TnyList *selected_attachments = NULL;
2565 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2566 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2568 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2569 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2571 return selected_attachments;
2575 ModestMsgViewWindow *self;
2577 } DecodeAsyncHelper;
2580 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2586 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2588 /* It could happen that the window was closed */
2589 if (GTK_WIDGET_VISIBLE (helper->self))
2590 set_progress_hint (helper->self, FALSE);
2592 if (cancelled || err) {
2594 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2595 modest_platform_information_banner (NULL, NULL, msg);
2601 /* make the file read-only */
2602 g_chmod(helper->file_path, 0444);
2604 /* Activate the file */
2605 modest_platform_activate_file (helper->file_path, tny_mime_part_get_content_type (mime_part));
2609 g_object_unref (helper->self);
2610 g_free (helper->file_path);
2611 g_slice_free (DecodeAsyncHelper, helper);
2615 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2616 TnyMimePart *mime_part)
2618 ModestMsgViewWindowPrivate *priv;
2619 const gchar *msg_uid;
2620 gchar *attachment_uid = NULL;
2621 gint attachment_index = 0;
2622 TnyList *attachments;
2624 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2625 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2626 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2628 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2629 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2630 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2631 g_object_unref (attachments);
2633 if (msg_uid && attachment_index >= 0) {
2634 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2637 if (mime_part == NULL) {
2638 gboolean error = FALSE;
2639 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2640 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2642 } else if (tny_list_get_length (selected_attachments) > 1) {
2643 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2647 iter = tny_list_create_iterator (selected_attachments);
2648 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2649 g_object_unref (iter);
2651 if (selected_attachments)
2652 g_object_unref (selected_attachments);
2657 g_object_ref (mime_part);
2660 if (tny_mime_part_is_purged (mime_part))
2663 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2664 gchar *filepath = NULL;
2665 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2666 gboolean show_error_banner = FALSE;
2667 TnyFsStream *temp_stream = NULL;
2668 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2671 if (temp_stream != NULL) {
2672 DecodeAsyncHelper *helper;
2674 /* Activate progress hint */
2675 set_progress_hint (window, TRUE);
2677 helper = g_slice_new0 (DecodeAsyncHelper);
2678 helper->self = g_object_ref (window);
2679 helper->file_path = g_strdup (filepath);
2681 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2682 on_decode_to_stream_async_handler,
2685 g_object_unref (temp_stream);
2686 /* NOTE: files in the temporary area will be automatically
2687 * cleaned after some time if they are no longer in use */
2690 const gchar *content_type;
2691 /* the file may already exist but it isn't writable,
2692 * let's try to open it anyway */
2693 content_type = tny_mime_part_get_content_type (mime_part);
2694 modest_platform_activate_file (filepath, content_type);
2696 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2697 show_error_banner = TRUE;
2702 if (show_error_banner)
2703 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2704 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2705 ModestWindowMgr *mgr;
2706 ModestWindow *msg_win = NULL;
2707 TnyMsg *current_msg;
2711 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2712 mgr = modest_runtime_get_window_mgr ();
2713 header = tny_msg_get_header (TNY_MSG (current_msg));
2714 found = modest_window_mgr_find_registered_message_uid (mgr,
2719 g_debug ("window for this body is already being created");
2722 /* it's not found, so create a new window for it */
2723 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2724 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2725 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2727 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2729 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part),
2730 account, mailbox, attachment_uid);
2732 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2733 modest_window_get_zoom (MODEST_WINDOW (window)));
2734 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2735 gtk_widget_show_all (GTK_WIDGET (msg_win));
2737 gtk_widget_destroy (GTK_WIDGET (msg_win));
2739 g_object_unref (current_msg);
2741 /* message attachment */
2742 TnyHeader *header = NULL;
2743 ModestWindowMgr *mgr;
2744 ModestWindow *msg_win = NULL;
2747 header = tny_msg_get_header (TNY_MSG (mime_part));
2748 mgr = modest_runtime_get_window_mgr ();
2749 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2752 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2753 * thus, we don't do anything */
2754 g_debug ("window for is already being created");
2756 /* it's not found, so create a new window for it */
2757 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2758 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2759 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2761 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2762 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account,
2763 mailbox, attachment_uid);
2764 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2765 modest_window_get_zoom (MODEST_WINDOW (window)));
2766 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2767 gtk_widget_show_all (GTK_WIDGET (msg_win));
2769 gtk_widget_destroy (GTK_WIDGET (msg_win));
2775 g_free (attachment_uid);
2777 g_object_unref (mime_part);
2789 GnomeVFSResult result;
2792 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2793 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2794 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2795 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
2798 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2802 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2803 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2804 g_free (pair->filename);
2805 g_object_unref (pair->part);
2806 g_slice_free (SaveMimePartPair, pair);
2808 g_list_free (info->pairs);
2811 g_slice_free (SaveMimePartInfo, info);
2816 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2818 if (info->pairs != NULL) {
2819 save_mime_part_to_file (info);
2821 /* This is a GDK lock because we are an idle callback and
2822 * hildon_banner_show_information is or does Gtk+ code */
2824 gdk_threads_enter (); /* CHECKED */
2825 save_mime_part_info_free (info, TRUE);
2826 if (info->result == GNOME_VFS_OK) {
2827 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2828 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
2829 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2830 modest_platform_information_banner (NULL, NULL, msg);
2833 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2835 gdk_threads_leave (); /* CHECKED */
2842 save_mime_part_to_file (SaveMimePartInfo *info)
2844 GnomeVFSHandle *handle;
2846 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2848 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2849 if (info->result == GNOME_VFS_OK) {
2850 GError *error = NULL;
2851 stream = tny_vfs_stream_new (handle);
2852 if (tny_mime_part_decode_to_stream (pair->part, stream, &error) < 0) {
2853 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
2855 if ((error->domain == TNY_ERROR_DOMAIN) &&
2856 (error->code == TNY_IO_ERROR_WRITE) &&
2857 (errno == ENOSPC)) {
2858 info->result = GNOME_VFS_ERROR_NO_SPACE;
2860 info->result = GNOME_VFS_ERROR_IO;
2863 g_object_unref (G_OBJECT (stream));
2864 g_object_unref (pair->part);
2865 g_slice_free (SaveMimePartPair, pair);
2866 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2868 g_warning ("Could not create save attachment %s: %s\n", pair->filename, gnome_vfs_result_to_string (info->result));
2869 save_mime_part_info_free (info, FALSE);
2872 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2877 save_mime_parts_to_file_with_checks (GtkWindow *parent,
2878 SaveMimePartInfo *info)
2880 gboolean is_ok = TRUE;
2881 gint replaced_files = 0;
2882 const GList *files = info->pairs;
2883 const GList *iter, *to_replace = NULL;
2885 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2886 SaveMimePartPair *pair = iter->data;
2887 if (modest_utils_file_exists (pair->filename)) {
2889 if (replaced_files == 1)
2893 if (replaced_files) {
2896 if (replaced_files == 1) {
2897 SaveMimePartPair *pair = to_replace->data;
2898 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
2899 gchar *escaped_basename, *message;
2901 escaped_basename = g_uri_unescape_string (basename, NULL);
2902 message = g_strdup_printf ("%s\n%s",
2903 _FM("docm_nc_replace_file"),
2904 (escaped_basename) ? escaped_basename : "");
2905 response = modest_platform_run_confirmation_dialog (parent, message);
2907 g_free (escaped_basename);
2909 response = modest_platform_run_confirmation_dialog (parent,
2910 _FM("docm_nc_replace_multiple"));
2912 if (response != GTK_RESPONSE_OK)
2917 save_mime_part_info_free (info, TRUE);
2919 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2925 save_attachments_response (GtkDialog *dialog,
2929 TnyList *mime_parts;
2931 GList *files_to_save = NULL;
2932 gchar *current_folder;
2934 mime_parts = TNY_LIST (user_data);
2936 if (arg1 != GTK_RESPONSE_OK)
2939 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
2940 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2941 if (current_folder && current_folder != '\0') {
2943 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
2944 current_folder,&err);
2946 g_debug ("Error storing latest used folder: %s", err->message);
2950 g_free (current_folder);
2952 if (!modest_utils_folder_writable (chooser_uri)) {
2953 hildon_banner_show_information
2954 (NULL, NULL, _FM("sfil_ib_readonly_location"));
2958 iter = tny_list_create_iterator (mime_parts);
2959 while (!tny_iterator_is_done (iter)) {
2960 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2962 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
2963 !tny_mime_part_is_purged (mime_part) &&
2964 (tny_mime_part_get_filename (mime_part) != NULL)) {
2965 SaveMimePartPair *pair;
2967 pair = g_slice_new0 (SaveMimePartPair);
2969 if (tny_list_get_length (mime_parts) > 1) {
2971 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
2972 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
2975 pair->filename = g_strdup (chooser_uri);
2977 pair->part = mime_part;
2978 files_to_save = g_list_prepend (files_to_save, pair);
2980 tny_iterator_next (iter);
2982 g_object_unref (iter);
2984 g_free (chooser_uri);
2986 if (files_to_save != NULL) {
2987 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2988 info->pairs = files_to_save;
2989 info->result = TRUE;
2990 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
2994 /* Free and close the dialog */
2995 g_object_unref (mime_parts);
2996 gtk_widget_destroy (GTK_WIDGET (dialog));
3000 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
3001 TnyList *mime_parts)
3003 ModestMsgViewWindowPrivate *priv;
3004 GtkWidget *save_dialog = NULL;
3005 gchar *conf_folder = NULL;
3006 gchar *filename = NULL;
3007 gchar *save_multiple_str = NULL;
3009 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3010 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3012 if (mime_parts == NULL) {
3013 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
3014 * selection available */
3015 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3016 if (mime_parts && !modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, FALSE)) {
3017 g_object_unref (mime_parts);
3020 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
3022 g_object_unref (mime_parts);
3028 g_object_ref (mime_parts);
3031 /* prepare dialog */
3032 if (tny_list_get_length (mime_parts) == 1) {
3034 /* only one attachment selected */
3035 iter = tny_list_create_iterator (mime_parts);
3036 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
3037 g_object_unref (iter);
3038 if (!modest_tny_mime_part_is_msg (mime_part) &&
3039 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
3040 !tny_mime_part_is_purged (mime_part)) {
3041 filename = g_strdup (tny_mime_part_get_filename (mime_part));
3043 /* TODO: show any error? */
3044 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
3045 g_object_unref (mime_parts);
3048 g_object_unref (mime_part);
3050 gint num = tny_list_get_length (mime_parts);
3051 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
3052 "sfil_va_number_of_objects_attachment",
3053 "sfil_va_number_of_objects_attachments",
3057 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
3058 GTK_FILE_CHOOSER_ACTION_SAVE);
3061 conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
3062 if (conf_folder && conf_folder[0] != '\0') {
3063 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
3066 /* Set the default folder to images folder */
3067 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
3068 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
3069 g_free (docs_folder);
3071 g_free (conf_folder);
3075 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
3080 /* if multiple, set multiple string */
3081 if (save_multiple_str) {
3082 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
3083 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
3086 /* We must run this asynchronously, because the hildon dialog
3087 performs a gtk_dialog_run by itself which leads to gdk
3089 g_signal_connect (save_dialog, "response",
3090 G_CALLBACK (save_attachments_response), mime_parts);
3092 gtk_widget_show_all (save_dialog);
3096 show_remove_attachment_information (gpointer userdata)
3098 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
3099 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3101 /* We're outside the main lock */
3102 gdk_threads_enter ();
3104 if (priv->remove_attachment_banner != NULL) {
3105 gtk_widget_destroy (priv->remove_attachment_banner);
3106 g_object_unref (priv->remove_attachment_banner);
3109 priv->remove_attachment_banner = g_object_ref (
3110 hildon_banner_show_animation (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
3112 gdk_threads_leave ();
3118 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
3120 ModestMsgViewWindowPrivate *priv;
3121 TnyList *mime_parts = NULL, *tmp;
3122 gchar *confirmation_message;
3128 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3129 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3131 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3132 * because we don't have selection
3134 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3136 /* Remove already purged messages from mime parts list. We use
3137 a copy of the list to remove items in the original one */
3138 tmp = tny_list_copy (mime_parts);
3139 iter = tny_list_create_iterator (tmp);
3140 while (!tny_iterator_is_done (iter)) {
3141 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3142 if (tny_mime_part_is_purged (part))
3143 tny_list_remove (mime_parts, (GObject *) part);
3145 g_object_unref (part);
3146 tny_iterator_next (iter);
3148 g_object_unref (tmp);
3149 g_object_unref (iter);
3151 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3152 tny_list_get_length (mime_parts) == 0) {
3153 g_object_unref (mime_parts);
3157 n_attachments = tny_list_get_length (mime_parts);
3158 if (n_attachments == 1) {
3162 iter = tny_list_create_iterator (mime_parts);
3163 part = (TnyMimePart *) tny_iterator_get_current (iter);
3164 g_object_unref (iter);
3165 if (modest_tny_mime_part_is_msg (part)) {
3167 header = tny_msg_get_header (TNY_MSG (part));
3168 filename = tny_header_dup_subject (header);
3169 g_object_unref (header);
3170 if (filename == NULL)
3171 filename = g_strdup (_("mail_va_no_subject"));
3173 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3175 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3177 g_object_unref (part);
3179 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3180 "mcen_nc_purge_files_text",
3181 n_attachments), n_attachments);
3183 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3184 confirmation_message);
3185 g_free (confirmation_message);
3187 if (response != GTK_RESPONSE_OK) {
3188 g_object_unref (mime_parts);
3192 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3194 iter = tny_list_create_iterator (mime_parts);
3195 while (!tny_iterator_is_done (iter)) {
3198 part = (TnyMimePart *) tny_iterator_get_current (iter);
3199 tny_mime_part_set_purged (TNY_MIME_PART (part));
3200 g_object_unref (part);
3201 tny_iterator_next (iter);
3203 g_object_unref (iter);
3205 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3206 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3207 tny_msg_rewrite_cache (msg);
3208 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3209 g_object_unref (msg);
3210 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3212 g_object_unref (mime_parts);
3214 if (priv->purge_timeout > 0) {
3215 g_source_remove (priv->purge_timeout);
3216 priv->purge_timeout = 0;
3219 if (priv->remove_attachment_banner) {
3220 gtk_widget_destroy (priv->remove_attachment_banner);
3221 g_object_unref (priv->remove_attachment_banner);
3222 priv->remove_attachment_banner = NULL;
3228 update_window_title (ModestMsgViewWindow *window)
3230 ModestMsgViewWindowPrivate *priv;
3232 TnyHeader *header = NULL;
3233 gchar *subject = NULL;
3235 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3237 /* Note that if the window is closed while we're retrieving
3238 the message, this widget could de deleted */
3239 if (!priv->msg_view)
3242 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3244 if (priv->other_body) {
3247 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3249 g_strstrip (description);
3250 subject = description;
3252 } else if (msg != NULL) {
3253 header = tny_msg_get_header (msg);
3254 subject = tny_header_dup_subject (header);
3255 g_object_unref (header);
3256 g_object_unref (msg);
3259 if ((subject == NULL)||(subject[0] == '\0')) {
3261 subject = g_strdup (_("mail_va_no_subject"));
3264 gtk_window_set_title (GTK_WINDOW (window), subject);
3269 on_move_focus (GtkWidget *widget,
3270 GtkDirectionType direction,
3273 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3277 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3279 GnomeVFSResult result;
3280 GnomeVFSHandle *handle = NULL;
3281 GnomeVFSFileInfo *info = NULL;
3284 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3285 if (result != GNOME_VFS_OK) {
3290 info = gnome_vfs_file_info_new ();
3291 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3292 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3293 /* We put a "safe" default size for going to cache */
3294 *expected_size = (300*1024);
3296 *expected_size = info->size;
3298 gnome_vfs_file_info_unref (info);
3300 stream = tny_vfs_stream_new (handle);
3309 TnyStream *output_stream;
3310 GtkWidget *msg_view;
3315 on_fetch_image_idle_refresh_view (gpointer userdata)
3318 FetchImageData *fidata = (FetchImageData *) userdata;
3320 gdk_threads_enter ();
3321 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3322 ModestMsgViewWindowPrivate *priv;
3324 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3325 priv->fetching_images--;
3326 gtk_widget_queue_draw (fidata->msg_view);
3327 update_progress_hint (MODEST_MSG_VIEW_WINDOW (fidata->window));
3329 gdk_threads_leave ();
3331 g_object_unref (fidata->msg_view);
3332 g_object_unref (fidata->window);
3333 g_slice_free (FetchImageData, fidata);
3338 on_fetch_image_thread (gpointer userdata)
3340 FetchImageData *fidata = (FetchImageData *) userdata;
3341 TnyStreamCache *cache;
3342 TnyStream *cache_stream;
3344 cache = modest_runtime_get_images_cache ();
3346 tny_stream_cache_get_stream (cache,
3348 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3349 (gpointer) fidata->uri);
3350 g_free (fidata->cache_id);
3351 g_free (fidata->uri);
3353 if (cache_stream != NULL) {
3356 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3359 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3360 if (G_UNLIKELY (nb_read < 0)) {
3362 } else if (G_LIKELY (nb_read > 0)) {
3363 gssize nb_written = 0;
3365 while (G_UNLIKELY (nb_written < nb_read)) {
3368 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3369 nb_read - nb_written);
3370 if (G_UNLIKELY (len < 0))
3376 tny_stream_close (cache_stream);
3377 g_object_unref (cache_stream);
3380 tny_stream_close (fidata->output_stream);
3381 g_object_unref (fidata->output_stream);
3383 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3389 on_fetch_image (ModestMsgView *msgview,
3392 ModestMsgViewWindow *window)
3394 const gchar *current_account;
3395 ModestMsgViewWindowPrivate *priv;
3396 FetchImageData *fidata;
3398 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3400 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3402 fidata = g_slice_new0 (FetchImageData);
3403 fidata->msg_view = g_object_ref (msgview);
3404 fidata->window = g_object_ref (window);
3405 fidata->uri = g_strdup (uri);
3406 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3407 fidata->output_stream = g_object_ref (stream);
3409 priv->fetching_images++;
3410 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3411 g_object_unref (fidata->output_stream);
3412 g_free (fidata->cache_id);
3413 g_free (fidata->uri);
3414 g_object_unref (fidata->msg_view);
3415 g_slice_free (FetchImageData, fidata);
3416 tny_stream_close (stream);
3417 priv->fetching_images--;
3418 update_progress_hint (window);
3421 update_progress_hint (window);
3427 setup_menu (ModestMsgViewWindow *self)
3429 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3431 /* Settings menu buttons */
3432 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_replytoall"), NULL,
3433 APP_MENU_CALLBACK (modest_ui_actions_on_reply_all),
3434 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3435 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_forward"), "<Control>d",
3436 APP_MENU_CALLBACK (modest_ui_actions_on_forward),
3437 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3439 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3440 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3441 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3442 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3443 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3444 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3446 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3447 APP_MENU_CALLBACK (modest_ui_actions_save_attachments),
3448 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3449 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3450 APP_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3451 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3453 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3454 APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3455 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3456 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3457 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3458 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3460 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mail_bd_external_images"), NULL,
3461 APP_MENU_CALLBACK (modest_ui_actions_on_fetch_images),
3462 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_fetch_images));
3463 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3464 APP_MENU_CALLBACK (modest_ui_actions_on_details),
3465 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3469 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3471 ModestMsgViewWindowPrivate *priv;
3472 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3473 GSList *recipients = NULL;
3475 gboolean contacts_to_add = FALSE;
3477 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3481 header = modest_msg_view_window_get_header (self);
3484 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3485 g_object_unref (header);
3487 recipients = modest_tny_msg_get_all_recipients_list (msg);
3488 g_object_unref (msg);
3491 if (recipients != NULL) {
3492 GtkWidget *picker_dialog;
3493 GtkWidget *selector;
3495 gchar *selected = NULL;
3497 selector = hildon_touch_selector_new_text ();
3498 g_object_ref (selector);
3500 for (node = recipients; node != NULL; node = g_slist_next (node)) {
3501 if (!modest_address_book_has_address ((const gchar *) node->data)) {
3502 hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector),
3503 (const gchar *) node->data);
3504 contacts_to_add = TRUE;
3508 if (contacts_to_add) {
3511 picker_dialog = hildon_picker_dialog_new (GTK_WINDOW (self));
3512 gtk_window_set_title (GTK_WINDOW (picker_dialog), _("mcen_me_viewer_addtocontacts"));
3514 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (picker_dialog),
3515 HILDON_TOUCH_SELECTOR (selector));
3517 picker_result = gtk_dialog_run (GTK_DIALOG (picker_dialog));
3519 if (picker_result == GTK_RESPONSE_OK) {
3520 selected = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
3522 gtk_widget_destroy (picker_dialog);
3525 modest_address_book_add_address (selected);
3530 g_object_unref (selector);
3535 if (recipients) {g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);}
3539 _modest_msg_view_window_map_event (GtkWidget *widget,
3543 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
3545 update_progress_hint (self);
3551 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
3553 ModestMsgViewWindowPrivate *priv;
3554 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3556 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
3560 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
3562 ModestMsgViewWindowPrivate *priv;
3563 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3565 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
3567 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
3571 modest_msg_view_window_reload (ModestMsgViewWindow *self)
3573 ModestMsgViewWindowPrivate *priv;
3576 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
3578 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3579 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
3581 if (!message_reader (self, priv, header, NULL, NULL, priv->row_reference)) {
3582 g_warning ("Shouldn't happen, trying to reload a message failed");
3585 g_object_unref (header);
3589 update_branding (ModestMsgViewWindow *self)
3591 const gchar *account;
3592 const gchar *mailbox;
3593 ModestAccountMgr *mgr;
3594 ModestProtocol *protocol = NULL;
3595 gchar *service_name = NULL;
3596 const GdkPixbuf *service_icon = NULL;
3597 ModestMsgViewWindowPrivate *priv;
3599 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3601 account = modest_window_get_active_account (MODEST_WINDOW (self));
3602 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
3604 mgr = modest_runtime_get_account_mgr ();
3606 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3607 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3608 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
3610 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
3611 account, mailbox, MODEST_ICON_SIZE_SMALL);
3615 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
3616 g_free (service_name);