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 GtkTreeRowReference *row_reference);
227 static void setup_menu (ModestMsgViewWindow *self);
228 static gboolean _modest_msg_view_window_map_event (GtkWidget *widget,
231 static void update_branding (ModestMsgViewWindow *self);
234 /* list my signals */
241 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
242 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
245 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
246 MODEST_TYPE_MSG_VIEW_WINDOW, \
247 ModestMsgViewWindowPrivate))
249 static GtkWindowClass *parent_class = NULL;
251 /* uncomment the following if you have defined any signals */
252 static guint signals[LAST_SIGNAL] = {0};
255 modest_msg_view_window_get_type (void)
257 static GType my_type = 0;
259 static const GTypeInfo my_info = {
260 sizeof(ModestMsgViewWindowClass),
261 NULL, /* base init */
262 NULL, /* base finalize */
263 (GClassInitFunc) modest_msg_view_window_class_init,
264 NULL, /* class finalize */
265 NULL, /* class data */
266 sizeof(ModestMsgViewWindow),
268 (GInstanceInitFunc) modest_msg_view_window_init,
271 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
272 "ModestMsgViewWindow",
275 static const GInterfaceInfo modest_header_view_observer_info =
277 (GInterfaceInitFunc) modest_header_view_observer_init,
278 NULL, /* interface_finalize */
279 NULL /* interface_data */
282 g_type_add_interface_static (my_type,
283 MODEST_TYPE_HEADER_VIEW_OBSERVER,
284 &modest_header_view_observer_info);
290 save_state (ModestWindow *self)
292 modest_widget_memory_save (modest_runtime_get_conf (),
294 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
298 gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self,
299 GtkScrollType scroll_type,
303 ModestMsgViewWindowPrivate *priv;
304 gboolean return_value;
306 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
307 g_signal_emit_by_name (priv->main_scroll, "scroll-child", scroll_type, horizontal, &return_value);
312 add_scroll_binding (GtkBindingSet *binding_set,
314 GtkScrollType scroll)
316 guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
318 gtk_binding_entry_add_signal (binding_set, keyval, 0,
320 GTK_TYPE_SCROLL_TYPE, scroll,
321 G_TYPE_BOOLEAN, FALSE);
322 gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0,
324 GTK_TYPE_SCROLL_TYPE, scroll,
325 G_TYPE_BOOLEAN, FALSE);
329 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
331 GObjectClass *gobject_class;
332 HildonWindowClass *hildon_window_class;
333 ModestWindowClass *modest_window_class;
334 GtkBindingSet *binding_set;
336 gobject_class = (GObjectClass*) klass;
337 hildon_window_class = (HildonWindowClass *) klass;
338 modest_window_class = (ModestWindowClass *) klass;
340 parent_class = g_type_class_peek_parent (klass);
341 gobject_class->finalize = modest_msg_view_window_finalize;
343 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
344 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
345 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
346 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
347 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
348 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
350 modest_window_class->save_state_func = save_state;
352 klass->scroll_child = modest_msg_view_window_scroll_child;
354 signals[MSG_CHANGED_SIGNAL] =
355 g_signal_new ("msg-changed",
356 G_TYPE_FROM_CLASS (gobject_class),
358 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
360 modest_marshal_VOID__POINTER_POINTER,
361 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
363 signals[SCROLL_CHILD_SIGNAL] =
364 g_signal_new ("scroll-child",
365 G_TYPE_FROM_CLASS (gobject_class),
366 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
367 G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child),
369 modest_marshal_BOOLEAN__ENUM_BOOLEAN,
370 G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN);
372 binding_set = gtk_binding_set_by_class (klass);
373 add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP);
374 add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN);
375 add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP);
376 add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN);
377 add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START);
378 add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END);
380 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
384 static void modest_header_view_observer_init(
385 ModestHeaderViewObserverIface *iface_class)
387 iface_class->update_func = modest_msg_view_window_update_model_replaced;
391 modest_msg_view_window_init (ModestMsgViewWindow *obj)
393 ModestMsgViewWindowPrivate *priv;
394 ModestWindowPrivate *parent_priv = NULL;
395 GtkActionGroup *action_group = NULL;
396 GError *error = NULL;
397 GdkPixbuf *window_icon;
399 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
400 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
401 parent_priv->ui_manager = gtk_ui_manager_new();
403 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
404 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
406 /* Add common actions */
407 gtk_action_group_add_actions (action_group,
408 modest_action_entries,
409 G_N_ELEMENTS (modest_action_entries),
411 gtk_action_group_add_toggle_actions (action_group,
412 msg_view_toggle_action_entries,
413 G_N_ELEMENTS (msg_view_toggle_action_entries),
416 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
417 g_object_unref (action_group);
419 /* Load the UI definition */
420 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
423 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
424 g_error_free (error);
429 /* Add accelerators */
430 gtk_window_add_accel_group (GTK_WINDOW (obj),
431 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
433 priv->is_search_result = FALSE;
434 priv->is_outbox = FALSE;
436 priv->msg_view = NULL;
437 priv->header_model = NULL;
438 priv->header_folder_id = NULL;
439 priv->clipboard_change_handler = 0;
440 priv->queue_change_handler = 0;
441 priv->account_removed_handler = 0;
442 priv->row_changed_handler = 0;
443 priv->row_deleted_handler = 0;
444 priv->row_inserted_handler = 0;
445 priv->rows_reordered_handler = 0;
446 priv->progress_hint = FALSE;
447 priv->fetching_images = 0;
449 priv->optimized_view = FALSE;
450 priv->purge_timeout = 0;
451 priv->remove_attachment_banner = NULL;
452 priv->msg_uid = NULL;
453 priv->other_body = NULL;
455 priv->sighandlers = NULL;
458 init_window (MODEST_MSG_VIEW_WINDOW(obj));
460 /* Set window icon */
461 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
463 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
464 g_object_unref (window_icon);
467 hildon_program_add_window (hildon_program_get_instance(),
474 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
476 ModestMsgViewWindowPrivate *priv = NULL;
478 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
480 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
482 set_progress_hint (self, TRUE);
488 update_progress_hint (ModestMsgViewWindow *self)
490 ModestMsgViewWindowPrivate *priv;
491 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
493 if (GTK_WIDGET_VISIBLE (self)) {
494 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self),
495 (priv->progress_hint || (priv->fetching_images > 0))?1:0);
500 set_progress_hint (ModestMsgViewWindow *self,
503 ModestWindowPrivate *parent_priv;
504 ModestMsgViewWindowPrivate *priv;
506 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
508 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
509 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
511 /* Sets current progress hint */
512 priv->progress_hint = enabled;
514 update_progress_hint (self);
520 init_window (ModestMsgViewWindow *obj)
522 GtkWidget *main_vbox;
523 ModestMsgViewWindowPrivate *priv;
525 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
527 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
528 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
529 main_vbox = gtk_vbox_new (FALSE, 6);
530 priv->main_scroll = hildon_pannable_area_new ();
531 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
532 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
533 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
535 priv->find_toolbar = hildon_find_toolbar_new (NULL);
536 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
537 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
539 /* NULL-ize fields if the window is destroyed */
540 g_signal_connect (priv->msg_view, "destroy", G_CALLBACK (gtk_widget_destroyed), &(priv->msg_view));
542 gtk_widget_show_all (GTK_WIDGET(main_vbox));
546 modest_msg_view_window_disconnect_signals (ModestWindow *self)
548 ModestMsgViewWindowPrivate *priv;
549 GtkWidget *header_view = NULL;
550 GtkWindow *parent_window = NULL;
552 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
554 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
555 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
556 priv->clipboard_change_handler))
557 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
558 priv->clipboard_change_handler);
560 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
561 priv->queue_change_handler))
562 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
563 priv->queue_change_handler);
565 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
566 priv->account_removed_handler))
567 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
568 priv->account_removed_handler);
570 if (priv->header_model) {
571 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
572 priv->row_changed_handler))
573 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
574 priv->row_changed_handler);
576 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
577 priv->row_deleted_handler))
578 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
579 priv->row_deleted_handler);
581 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
582 priv->row_inserted_handler))
583 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
584 priv->row_inserted_handler);
586 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
587 priv->rows_reordered_handler))
588 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
589 priv->rows_reordered_handler);
592 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
593 priv->sighandlers = NULL;
595 parent_window = gtk_window_get_transient_for (GTK_WINDOW (self));
596 if (parent_window && MODEST_IS_HEADER_WINDOW (parent_window)) {
597 header_view = GTK_WIDGET (modest_header_window_get_header_view (MODEST_HEADER_WINDOW (parent_window)));
599 modest_header_view_remove_observer(MODEST_HEADER_VIEW (header_view),
600 MODEST_HEADER_VIEW_OBSERVER(self));
606 modest_msg_view_window_finalize (GObject *obj)
608 ModestMsgViewWindowPrivate *priv;
610 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
612 /* Sanity check: shouldn't be needed, the window mgr should
613 call this function before */
614 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
616 if (priv->other_body != NULL) {
617 g_object_unref (priv->other_body);
618 priv->other_body = NULL;
621 if (priv->header_model != NULL) {
622 g_object_unref (priv->header_model);
623 priv->header_model = NULL;
626 if (priv->remove_attachment_banner) {
627 gtk_widget_destroy (priv->remove_attachment_banner);
628 g_object_unref (priv->remove_attachment_banner);
629 priv->remove_attachment_banner = NULL;
632 if (priv->purge_timeout > 0) {
633 g_source_remove (priv->purge_timeout);
634 priv->purge_timeout = 0;
637 if (priv->row_reference) {
638 gtk_tree_row_reference_free (priv->row_reference);
639 priv->row_reference = NULL;
642 if (priv->next_row_reference) {
643 gtk_tree_row_reference_free (priv->next_row_reference);
644 priv->next_row_reference = NULL;
648 g_free (priv->msg_uid);
649 priv->msg_uid = NULL;
652 G_OBJECT_CLASS(parent_class)->finalize (obj);
656 select_next_valid_row (GtkTreeModel *model,
657 GtkTreeRowReference **row_reference,
661 GtkTreeIter tmp_iter;
663 GtkTreePath *next = NULL;
664 gboolean retval = FALSE, finished;
666 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
668 path = gtk_tree_row_reference_get_path (*row_reference);
669 gtk_tree_model_get_iter (model, &tmp_iter, path);
670 gtk_tree_row_reference_free (*row_reference);
671 *row_reference = NULL;
675 TnyHeader *header = NULL;
677 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
678 gtk_tree_model_get (model, &tmp_iter,
679 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
683 if (msg_is_visible (header, is_outbox)) {
684 next = gtk_tree_model_get_path (model, &tmp_iter);
685 *row_reference = gtk_tree_row_reference_new (model, next);
686 gtk_tree_path_free (next);
690 g_object_unref (header);
693 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
694 next = gtk_tree_model_get_path (model, &tmp_iter);
696 /* Ensure that we are not selecting the same */
697 if (gtk_tree_path_compare (path, next) != 0) {
698 gtk_tree_model_get (model, &tmp_iter,
699 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
702 if (msg_is_visible (header, is_outbox)) {
703 *row_reference = gtk_tree_row_reference_new (model, next);
707 g_object_unref (header);
711 /* If we ended up in the same message
712 then there is no valid next
716 gtk_tree_path_free (next);
718 /* If there are no more messages and we don't
719 want to start again in the first one then
720 there is no valid next message */
726 gtk_tree_path_free (path);
731 /* TODO: This should be in _init(), with the parameters as properties. */
733 modest_msg_view_window_construct (ModestMsgViewWindow *self,
734 const gchar *modest_account_name,
735 const gchar *mailbox,
736 const gchar *msg_uid)
739 ModestMsgViewWindowPrivate *priv = NULL;
740 ModestWindowPrivate *parent_priv = NULL;
741 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
742 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
744 obj = G_OBJECT (self);
745 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
746 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
748 priv->msg_uid = g_strdup (msg_uid);
751 parent_priv->menubar = NULL;
753 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
754 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
757 /* Add common dimming rules */
758 modest_dimming_rules_group_add_rules (toolbar_rules_group,
759 modest_msg_view_toolbar_dimming_entries,
760 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
761 MODEST_WINDOW (self));
762 modest_dimming_rules_group_add_rules (clipboard_rules_group,
763 modest_msg_view_clipboard_dimming_entries,
764 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
765 MODEST_WINDOW (self));
767 /* Insert dimming rules group for this window */
768 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
769 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
770 g_object_unref (toolbar_rules_group);
771 g_object_unref (clipboard_rules_group);
773 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
775 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);
776 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
777 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
778 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
779 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
780 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
781 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
782 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
783 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
784 g_signal_connect (G_OBJECT(priv->msg_view), "show_details",
785 G_CALLBACK (modest_ui_actions_on_details), obj);
786 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
787 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
788 g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image",
789 G_CALLBACK (on_fetch_image), obj);
791 g_signal_connect (G_OBJECT (obj), "key-release-event",
792 G_CALLBACK (modest_msg_view_window_key_event),
795 g_signal_connect (G_OBJECT (obj), "key-press-event",
796 G_CALLBACK (modest_msg_view_window_key_event),
799 g_signal_connect (G_OBJECT (obj), "move-focus",
800 G_CALLBACK (on_move_focus), obj);
802 g_signal_connect (G_OBJECT (obj), "map-event",
803 G_CALLBACK (_modest_msg_view_window_map_event),
806 /* Mail Operation Queue */
807 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
809 G_CALLBACK (on_queue_changed),
812 /* Account manager */
813 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
815 G_CALLBACK(on_account_removed),
818 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
819 modest_window_set_active_mailbox (MODEST_WINDOW(obj), mailbox);
821 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
822 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
823 priv->last_search = NULL;
825 modest_msg_view_window_show_toolbar (MODEST_WINDOW (obj), TRUE);
827 /* Init the clipboard actions dim status */
828 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
830 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
835 /* FIXME: parameter checks */
837 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
838 const gchar *modest_account_name,
839 const gchar *mailbox,
840 const gchar *msg_uid,
842 GtkTreeRowReference *row_reference)
844 ModestMsgViewWindow *window = NULL;
845 ModestMsgViewWindowPrivate *priv = NULL;
846 TnyFolder *header_folder = NULL;
847 ModestHeaderView *header_view = NULL;
848 ModestWindowMgr *mgr = NULL;
851 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
854 mgr = modest_runtime_get_window_mgr ();
855 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
856 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
858 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
860 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
862 /* Remember the message list's TreeModel so we can detect changes
863 * and change the list selection when necessary: */
864 header_folder = modest_header_view_get_folder (header_view);
866 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
867 TNY_FOLDER_TYPE_OUTBOX);
868 priv->header_folder_id = tny_folder_get_id (header_folder);
869 g_object_unref(header_folder);
872 /* Setup row references and connect signals */
873 priv->header_model = g_object_ref (model);
876 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
877 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
878 select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox);
880 priv->row_reference = NULL;
881 priv->next_row_reference = NULL;
884 /* Connect signals */
885 priv->row_changed_handler =
886 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
887 G_CALLBACK(modest_msg_view_window_on_row_changed),
889 priv->row_deleted_handler =
890 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
891 G_CALLBACK(modest_msg_view_window_on_row_deleted),
893 priv->row_inserted_handler =
894 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
895 G_CALLBACK(modest_msg_view_window_on_row_inserted),
897 priv->rows_reordered_handler =
898 g_signal_connect(GTK_TREE_MODEL(model), "rows-reordered",
899 G_CALLBACK(modest_msg_view_window_on_row_reordered),
902 if (header_view != NULL){
903 modest_header_view_add_observer(header_view,
904 MODEST_HEADER_VIEW_OBSERVER(window));
907 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
908 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
909 update_branding (MODEST_MSG_VIEW_WINDOW (window));
911 /* gtk_widget_show_all (GTK_WIDGET (window)); */
912 modest_msg_view_window_update_priority (window);
913 /* Check dimming rules */
914 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
915 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
916 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
918 return MODEST_WINDOW(window);
922 modest_msg_view_window_new_from_header_view (ModestHeaderView *header_view,
923 const gchar *modest_account_name,
924 const gchar *mailbox,
925 const gchar *msg_uid,
926 GtkTreeRowReference *row_reference)
928 ModestMsgViewWindow *window = NULL;
929 ModestMsgViewWindowPrivate *priv = NULL;
930 TnyFolder *header_folder = NULL;
931 ModestWindowMgr *mgr = NULL;
935 mgr = modest_runtime_get_window_mgr ();
936 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
937 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
939 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
941 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
943 /* Remember the message list's TreeModel so we can detect changes
944 * and change the list selection when necessary: */
946 if (header_view != NULL){
947 header_folder = modest_header_view_get_folder(header_view);
948 /* This could happen if the header folder was
949 unseleted before opening this msg window (for
950 example if the user selects an account in the
951 folder view of the main window */
953 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) ==
954 TNY_FOLDER_TYPE_OUTBOX);
955 priv->header_folder_id = tny_folder_get_id(header_folder);
956 g_object_unref(header_folder);
960 /* Setup row references and connect signals */
961 priv->header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
962 g_object_ref (priv->header_model);
965 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
966 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
967 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
969 priv->row_reference = NULL;
970 priv->next_row_reference = NULL;
973 /* Connect signals */
974 priv->row_changed_handler =
975 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-changed",
976 G_CALLBACK(modest_msg_view_window_on_row_changed),
978 priv->row_deleted_handler =
979 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-deleted",
980 G_CALLBACK(modest_msg_view_window_on_row_deleted),
982 priv->row_inserted_handler =
983 g_signal_connect (GTK_TREE_MODEL(priv->header_model), "row-inserted",
984 G_CALLBACK(modest_msg_view_window_on_row_inserted),
986 priv->rows_reordered_handler =
987 g_signal_connect(GTK_TREE_MODEL(priv->header_model), "rows-reordered",
988 G_CALLBACK(modest_msg_view_window_on_row_reordered),
991 if (header_view != NULL){
992 modest_header_view_add_observer(header_view,
993 MODEST_HEADER_VIEW_OBSERVER(window));
996 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), NULL);
997 update_branding (MODEST_MSG_VIEW_WINDOW (window));
999 path = gtk_tree_row_reference_get_path (row_reference);
1000 if (gtk_tree_model_get_iter (priv->header_model, &iter, path)) {
1002 gtk_tree_model_get (priv->header_model, &iter,
1003 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1005 message_reader (window, priv, header, row_reference);
1006 g_object_unref (header);
1008 gtk_tree_path_free (path);
1010 /* Check dimming rules */
1011 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1012 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1013 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1015 return MODEST_WINDOW(window);
1019 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
1020 const gchar *modest_account_name,
1021 const gchar *mailbox,
1022 const gchar *msg_uid)
1024 ModestMsgViewWindow *window = NULL;
1025 ModestMsgViewWindowPrivate *priv = NULL;
1026 ModestWindowMgr *mgr = NULL;
1028 mgr = modest_runtime_get_window_mgr ();
1029 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
1030 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
1031 modest_msg_view_window_construct (window, modest_account_name, mailbox, msg_uid);
1033 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1035 /* Remember that this is a search result,
1036 * so we can disable some UI appropriately: */
1037 priv->is_search_result = TRUE;
1039 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1040 update_branding (MODEST_MSG_VIEW_WINDOW (window));
1042 update_window_title (window);
1043 /* gtk_widget_show_all (GTK_WIDGET (window));*/
1044 modest_msg_view_window_update_priority (window);
1046 /* Check dimming rules */
1047 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1048 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1049 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
1051 return MODEST_WINDOW(window);
1055 modest_msg_view_window_is_other_body (ModestMsgViewWindow *self)
1057 ModestMsgViewWindowPrivate *priv = NULL;
1059 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1060 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1062 return (priv->other_body != NULL);
1066 modest_msg_view_window_new_with_other_body (TnyMsg *msg,
1067 TnyMimePart *other_body,
1068 const gchar *modest_account_name,
1069 const gchar *mailbox,
1070 const gchar *msg_uid)
1072 GObject *obj = NULL;
1073 ModestMsgViewWindowPrivate *priv;
1074 ModestWindowMgr *mgr = NULL;
1076 g_return_val_if_fail (msg, NULL);
1077 mgr = modest_runtime_get_window_mgr ();
1078 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
1079 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1080 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
1081 modest_account_name, mailbox, msg_uid);
1084 priv->other_body = g_object_ref (other_body);
1085 modest_msg_view_set_msg_with_other_body (MODEST_MSG_VIEW (priv->msg_view), msg, other_body);
1087 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1089 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
1090 update_branding (MODEST_MSG_VIEW_WINDOW (obj));
1092 /* gtk_widget_show_all (GTK_WIDGET (obj)); */
1094 /* Check dimming rules */
1095 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
1096 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
1097 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
1099 return MODEST_WINDOW(obj);
1103 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
1104 const gchar *modest_account_name,
1105 const gchar *mailbox,
1106 const gchar *msg_uid)
1108 return modest_msg_view_window_new_with_other_body (msg, NULL, modest_account_name, mailbox, msg_uid);
1112 modest_msg_view_window_on_row_changed (GtkTreeModel *header_model,
1115 ModestMsgViewWindow *window)
1117 check_dimming_rules_after_change (window);
1121 modest_msg_view_window_on_row_deleted(GtkTreeModel *header_model,
1123 ModestMsgViewWindow *window)
1125 check_dimming_rules_after_change (window);
1127 /* The window could have dissapeared */
1130 check_dimming_rules_after_change (ModestMsgViewWindow *window)
1132 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
1133 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1137 /* On insertions we check if the folder still has the message we are
1138 * showing or do not. If do not, we do nothing. Which means we are still
1139 * not attached to any header folder and thus next/prev buttons are
1140 * still dimmed. Once the message that is shown by msg-view is found, the
1141 * new model of header-view will be attached and the references will be set.
1142 * On each further insertions dimming rules will be checked. However
1143 * this requires extra CPU time at least works.
1144 * (An message might be deleted from TnyFolder and thus will not be
1145 * inserted into the model again for example if it is removed by the
1146 * imap server and the header view is refreshed.)
1149 modest_msg_view_window_on_row_inserted (GtkTreeModel *model,
1150 GtkTreePath *tree_path,
1151 GtkTreeIter *tree_iter,
1152 ModestMsgViewWindow *window)
1154 ModestMsgViewWindowPrivate *priv = NULL;
1155 TnyHeader *header = NULL;
1157 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1158 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1160 g_assert (model == priv->header_model);
1162 /* Check if the newly inserted message is the same we are actually
1163 * showing. IF not, we should remain detached from the header model
1164 * and thus prev and next toolbar buttons should remain dimmed. */
1165 gtk_tree_model_get (model, tree_iter,
1166 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1169 if (TNY_IS_HEADER (header)) {
1172 uid = modest_tny_folder_get_header_unique_id (header);
1173 if (!g_str_equal(priv->msg_uid, uid)) {
1174 check_dimming_rules_after_change (window);
1176 g_object_unref (G_OBJECT(header));
1180 g_object_unref(G_OBJECT(header));
1183 if (priv->row_reference) {
1184 gtk_tree_row_reference_free (priv->row_reference);
1187 /* Setup row_reference for the actual msg. */
1188 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, tree_path);
1189 if (priv->row_reference == NULL) {
1190 g_warning("%s: No reference for msg header item.", __FUNCTION__);
1194 /* Now set up next_row_reference. */
1195 if (priv->next_row_reference) {
1196 gtk_tree_row_reference_free (priv->next_row_reference);
1199 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1200 select_next_valid_row (priv->header_model,
1201 &(priv->next_row_reference), FALSE, priv->is_outbox);
1203 /* Connect the remaining callbacks to become able to detect
1204 * changes in header-view. */
1205 priv->row_changed_handler =
1206 g_signal_connect (priv->header_model, "row-changed",
1207 G_CALLBACK (modest_msg_view_window_on_row_changed),
1209 priv->row_deleted_handler =
1210 g_signal_connect (priv->header_model, "row-deleted",
1211 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1213 priv->rows_reordered_handler =
1214 g_signal_connect (priv->header_model, "rows-reordered",
1215 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1218 check_dimming_rules_after_change (window);
1222 modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model,
1226 ModestMsgViewWindow *window)
1228 ModestMsgViewWindowPrivate *priv = NULL;
1229 gboolean already_changed = FALSE;
1231 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1233 /* If the current row was reordered select the proper next
1234 valid row. The same if the next row reference changes */
1235 if (priv->row_reference &&
1236 gtk_tree_row_reference_valid (priv->row_reference)) {
1238 path = gtk_tree_row_reference_get_path (priv->row_reference);
1239 if (gtk_tree_path_compare (path, arg1) == 0) {
1240 if (priv->next_row_reference) {
1241 gtk_tree_row_reference_free (priv->next_row_reference);
1243 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1244 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1245 already_changed = TRUE;
1247 gtk_tree_path_free (path);
1249 if (!already_changed &&
1250 priv->next_row_reference &&
1251 gtk_tree_row_reference_valid (priv->next_row_reference)) {
1253 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1254 if (gtk_tree_path_compare (path, arg1) == 0) {
1255 if (priv->next_row_reference) {
1256 gtk_tree_row_reference_free (priv->next_row_reference);
1258 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1259 select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1261 gtk_tree_path_free (path);
1263 check_dimming_rules_after_change (window);
1266 /* The modest_msg_view_window_update_model_replaced implements update
1267 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1268 * actually belongs to the header-view is the same as the TnyFolder of
1269 * the message of msg-view or not. If they are different, there is
1270 * nothing to do. If they are the same, then the model has replaced and
1271 * the reference in msg-view shall be replaced from the old model to
1272 * the new model. In this case the view will be detached from it's
1273 * header folder. From this point the next/prev buttons are dimmed.
1276 modest_msg_view_window_update_model_replaced (ModestHeaderViewObserver *observer,
1277 GtkTreeModel *model,
1278 const gchar *tny_folder_id)
1280 ModestMsgViewWindowPrivate *priv = NULL;
1281 ModestMsgViewWindow *window = NULL;
1283 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1284 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1286 window = MODEST_MSG_VIEW_WINDOW(observer);
1287 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1289 /* If there is an other folder in the header-view then we do
1290 * not care about it's model (msg list). Else if the
1291 * header-view shows the folder the msg shown by us is in, we
1292 * shall replace our model reference and make some check. */
1293 if(model == NULL || tny_folder_id == NULL ||
1294 (priv->header_folder_id && !g_str_equal(tny_folder_id, priv->header_folder_id)))
1297 /* Model is changed(replaced), so we should forget the old
1298 * one. Because there might be other references and there
1299 * might be some change on the model even if we unreferenced
1300 * it, we need to disconnect our signals here. */
1301 if (priv->header_model) {
1302 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1303 priv->row_changed_handler))
1304 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1305 priv->row_changed_handler);
1306 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1307 priv->row_deleted_handler))
1308 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1309 priv->row_deleted_handler);
1310 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1311 priv->row_inserted_handler))
1312 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1313 priv->row_inserted_handler);
1314 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1315 priv->rows_reordered_handler))
1316 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1317 priv->rows_reordered_handler);
1320 if (priv->row_reference)
1321 gtk_tree_row_reference_free (priv->row_reference);
1322 if (priv->next_row_reference)
1323 gtk_tree_row_reference_free (priv->next_row_reference);
1324 g_object_unref(priv->header_model);
1327 priv->row_changed_handler = 0;
1328 priv->row_deleted_handler = 0;
1329 priv->row_inserted_handler = 0;
1330 priv->rows_reordered_handler = 0;
1331 priv->next_row_reference = NULL;
1332 priv->row_reference = NULL;
1333 priv->header_model = NULL;
1336 priv->header_model = g_object_ref (model);
1338 /* Also we must connect to the new model for row insertions.
1339 * Only for insertions now. We will need other ones only after
1340 * the msg is show by msg-view is added to the new model. */
1341 priv->row_inserted_handler =
1342 g_signal_connect (priv->header_model, "row-inserted",
1343 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1346 modest_ui_actions_check_menu_dimming_rules(MODEST_WINDOW(window));
1347 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1351 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1353 ModestMsgViewWindowPrivate *priv= NULL;
1355 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1356 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1358 return priv->progress_hint;
1362 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1364 ModestMsgViewWindowPrivate *priv= NULL;
1366 TnyHeader *header = NULL;
1367 GtkTreePath *path = NULL;
1370 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1371 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1373 /* If the message was not obtained from a treemodel,
1374 * for instance if it was opened directly by the search UI:
1376 if (priv->header_model == NULL ||
1377 priv->row_reference == NULL ||
1378 !gtk_tree_row_reference_valid (priv->row_reference)) {
1379 msg = modest_msg_view_window_get_message (self);
1381 header = tny_msg_get_header (msg);
1382 g_object_unref (msg);
1387 /* Get iter of the currently selected message in the header view: */
1388 path = gtk_tree_row_reference_get_path (priv->row_reference);
1389 g_return_val_if_fail (path != NULL, NULL);
1390 gtk_tree_model_get_iter (priv->header_model,
1394 /* Get current message header */
1395 gtk_tree_model_get (priv->header_model, &iter,
1396 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1399 gtk_tree_path_free (path);
1404 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1406 ModestMsgViewWindowPrivate *priv;
1408 g_return_val_if_fail (self, NULL);
1410 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1412 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1416 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1418 ModestMsgViewWindowPrivate *priv;
1420 g_return_val_if_fail (self, NULL);
1422 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1424 return (const gchar*) priv->msg_uid;
1428 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1431 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1432 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1433 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1437 is_active = gtk_toggle_action_get_active (toggle);
1440 gtk_widget_show (priv->find_toolbar);
1441 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1443 gtk_widget_hide (priv->find_toolbar);
1444 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1447 /* update the toggle buttons status */
1448 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1450 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1455 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1456 ModestMsgViewWindow *obj)
1458 GtkToggleAction *toggle;
1459 ModestWindowPrivate *parent_priv;
1460 ModestMsgViewWindowPrivate *priv;
1462 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1463 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1465 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1466 gtk_toggle_action_set_active (toggle, FALSE);
1467 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1471 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1472 ModestMsgViewWindow *obj)
1474 gchar *current_search;
1475 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1477 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1478 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1482 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1484 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1485 g_free (current_search);
1486 hildon_banner_show_information (NULL, NULL, _CS("ecdg_ib_find_rep_enter_text"));
1490 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1492 g_free (priv->last_search);
1493 priv->last_search = g_strdup (current_search);
1494 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1497 hildon_banner_show_information (NULL, NULL,
1498 _HL("ckct_ib_find_no_matches"));
1499 g_free (priv->last_search);
1500 priv->last_search = NULL;
1502 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1505 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1506 hildon_banner_show_information (NULL, NULL,
1507 _HL("ckct_ib_find_search_complete"));
1508 g_free (priv->last_search);
1509 priv->last_search = NULL;
1511 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1515 g_free (current_search);
1520 modest_msg_view_window_set_zoom (ModestWindow *window,
1523 ModestMsgViewWindowPrivate *priv;
1524 ModestWindowPrivate *parent_priv;
1526 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1528 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1529 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1530 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1535 modest_msg_view_window_get_zoom (ModestWindow *window)
1537 ModestMsgViewWindowPrivate *priv;
1539 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1541 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1542 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1546 modest_msg_view_window_zoom_plus (ModestWindow *window)
1549 ModestMsgViewWindowPrivate *priv;
1553 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1554 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1556 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1558 if (zoom_level >= 2.0) {
1559 hildon_banner_show_information (NULL, NULL,
1560 _CS("ckct_ib_max_zoom_level_reached"));
1562 } else if (zoom_level >= 1.5) {
1564 } else if (zoom_level >= 1.2) {
1566 } else if (zoom_level >= 1.0) {
1568 } else if (zoom_level >= 0.8) {
1570 } else if (zoom_level >= 0.5) {
1576 /* set zoom level */
1577 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1578 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1579 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1580 g_free (banner_text);
1581 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1587 modest_msg_view_window_zoom_minus (ModestWindow *window)
1590 ModestMsgViewWindowPrivate *priv;
1594 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1595 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1597 zoom_level = modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1599 if (zoom_level <= 0.5) {
1600 hildon_banner_show_information (NULL, NULL,
1601 _CS("ckct_ib_min_zoom_level_reached"));
1603 } else if (zoom_level <= 0.8) {
1605 } else if (zoom_level <= 1.0) {
1607 } else if (zoom_level <= 1.2) {
1609 } else if (zoom_level <= 1.5) {
1611 } else if (zoom_level <= 2.0) {
1617 /* set zoom level */
1618 int_zoom = (gint) rint (zoom_level*100.0+0.1);
1619 banner_text = g_strdup_printf (_HL("wdgt_ib_zoom"), int_zoom);
1620 modest_platform_information_banner (GTK_WIDGET (window), NULL, banner_text);
1621 g_free (banner_text);
1622 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom_level);
1629 modest_msg_view_window_key_event (GtkWidget *window,
1635 focus = gtk_window_get_focus (GTK_WINDOW (window));
1637 /* for the find toolbar case */
1638 if (focus && GTK_IS_ENTRY (focus)) {
1639 if (event->keyval == GDK_BackSpace) {
1641 copy = gdk_event_copy ((GdkEvent *) event);
1642 gtk_widget_event (focus, copy);
1643 gdk_event_free (copy);
1648 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1649 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1650 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1651 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1652 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1653 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1654 /* ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); */
1655 /* gboolean return_value; */
1657 if (event->type == GDK_KEY_PRESS) {
1658 GtkScrollType scroll_type;
1660 switch (event->keyval) {
1663 scroll_type = GTK_SCROLL_STEP_UP; break;
1666 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1668 case GDK_KP_Page_Up:
1669 scroll_type = GTK_SCROLL_PAGE_UP; break;
1671 case GDK_KP_Page_Down:
1672 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1675 scroll_type = GTK_SCROLL_START; break;
1678 scroll_type = GTK_SCROLL_END; break;
1679 default: scroll_type = GTK_SCROLL_NONE;
1682 /* g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", */
1683 /* scroll_type, FALSE, &return_value); */
1694 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1697 ModestMsgViewWindowPrivate *priv;
1698 GtkTreeIter tmp_iter;
1699 gboolean is_last_selected;
1701 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1702 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1704 /*if no model (so no rows at all), then virtually we are the last*/
1705 if (!priv->header_model || !priv->row_reference)
1708 if (!gtk_tree_row_reference_valid (priv->row_reference))
1711 path = gtk_tree_row_reference_get_path (priv->row_reference);
1715 is_last_selected = TRUE;
1716 while (is_last_selected) {
1718 gtk_tree_path_next (path);
1719 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1721 gtk_tree_model_get (priv->header_model, &tmp_iter,
1722 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1725 if (msg_is_visible (header, priv->is_outbox))
1726 is_last_selected = FALSE;
1727 g_object_unref(G_OBJECT(header));
1730 gtk_tree_path_free (path);
1731 return is_last_selected;
1735 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1737 ModestMsgViewWindowPrivate *priv;
1739 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1740 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1742 return priv->header_model != NULL;
1746 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1748 ModestMsgViewWindowPrivate *priv;
1750 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1751 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1753 return priv->is_search_result;
1757 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1759 if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1761 if (!check_outbox) {
1764 ModestTnySendQueueStatus status;
1765 status = modest_tny_all_send_queues_get_msg_status (header);
1766 return ((status != MODEST_TNY_SEND_QUEUE_FAILED) &&
1767 (status != MODEST_TNY_SEND_QUEUE_SENDING));
1772 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1775 ModestMsgViewWindowPrivate *priv;
1776 gboolean is_first_selected;
1777 GtkTreeIter tmp_iter;
1779 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1780 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1782 /*if no model (so no rows at all), then virtually we are the first*/
1783 if (!priv->header_model || !priv->row_reference)
1786 if (!gtk_tree_row_reference_valid (priv->row_reference))
1789 path = gtk_tree_row_reference_get_path (priv->row_reference);
1793 is_first_selected = TRUE;
1794 while (is_first_selected) {
1796 if(!gtk_tree_path_prev (path))
1798 /* Here the 'if' is needless for logic, but let make sure
1799 * iter is valid for gtk_tree_model_get. */
1800 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1802 gtk_tree_model_get (priv->header_model, &tmp_iter,
1803 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1806 if (msg_is_visible (header, priv->is_outbox))
1807 is_first_selected = FALSE;
1808 g_object_unref(G_OBJECT(header));
1811 gtk_tree_path_free (path);
1812 return is_first_selected;
1817 GtkTreeRowReference *row_reference;
1821 message_reader_performer (gboolean canceled,
1823 GtkWindow *parent_window,
1824 TnyAccount *account,
1827 ModestMailOperation *mail_op = NULL;
1828 MsgReaderInfo *info;
1830 info = (MsgReaderInfo *) user_data;
1831 if (canceled || err) {
1832 update_window_title (MODEST_MSG_VIEW_WINDOW (parent_window));
1836 /* Register the header - it'll be unregistered in the callback */
1837 modest_window_mgr_register_header (modest_runtime_get_window_mgr (), info->header, NULL);
1839 /* New mail operation */
1840 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1841 modest_ui_actions_disk_operations_error_handler,
1844 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1845 modest_mail_operation_get_msg (mail_op, info->header, TRUE, view_msg_cb, info->row_reference);
1846 g_object_unref (mail_op);
1848 /* Update dimming rules */
1849 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1850 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1853 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1854 g_object_unref (info->header);
1855 g_slice_free (MsgReaderInfo, info);
1860 * Reads the message whose summary item is @header. It takes care of
1861 * several things, among others:
1863 * If the message was not previously downloaded then ask the user
1864 * before downloading. If there is no connection launch the connection
1865 * dialog. Update toolbar dimming rules.
1867 * Returns: TRUE if the mail operation was started, otherwise if the
1868 * user do not want to download the message, or if the user do not
1869 * want to connect, then the operation is not issued
1872 message_reader (ModestMsgViewWindow *window,
1873 ModestMsgViewWindowPrivate *priv,
1875 GtkTreeRowReference *row_reference)
1877 ModestWindowMgr *mgr;
1878 TnyAccount *account;
1880 MsgReaderInfo *info;
1882 g_return_val_if_fail (row_reference != NULL, FALSE);
1884 /* We set the header from model while we're loading */
1885 tny_header_view_set_header (TNY_HEADER_VIEW (priv->msg_view), header);
1886 gtk_window_set_title (GTK_WINDOW (window), _CS("ckdg_pb_updating"));
1888 mgr = modest_runtime_get_window_mgr ();
1889 /* Msg download completed */
1890 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1892 /* Ask the user if he wants to download the message if
1894 if (!tny_device_is_online (modest_runtime_get_device())) {
1895 GtkResponseType response;
1897 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1898 _("mcen_nc_get_msg"));
1899 if (response == GTK_RESPONSE_CANCEL) {
1900 update_window_title (window);
1904 folder = tny_header_get_folder (header);
1905 info = g_slice_new (MsgReaderInfo);
1906 info->header = g_object_ref (header);
1907 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1909 /* Offer the connection dialog if necessary */
1910 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
1912 TNY_FOLDER_STORE (folder),
1913 message_reader_performer,
1915 g_object_unref (folder);
1920 folder = tny_header_get_folder (header);
1921 account = tny_folder_get_account (folder);
1922 info = g_slice_new (MsgReaderInfo);
1923 info->header = g_object_ref (header);
1924 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1926 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
1927 g_object_unref (account);
1928 g_object_unref (folder);
1934 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1936 ModestMsgViewWindowPrivate *priv;
1937 GtkTreePath *path= NULL;
1938 GtkTreeIter tmp_iter;
1940 gboolean retval = TRUE;
1941 GtkTreeRowReference *row_reference = NULL;
1943 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1944 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1946 if (!priv->row_reference)
1949 /* Update the next row reference if it's not valid. This could
1950 happen if for example the header which it was pointing to,
1951 was deleted. The best place to do it is in the row-deleted
1952 handler but the tinymail model do not work like the glib
1953 tree models and reports the deletion when the row is still
1955 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1956 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1957 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1958 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox);
1961 if (priv->next_row_reference)
1962 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1966 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1968 gtk_tree_model_get_iter (priv->header_model,
1971 gtk_tree_path_free (path);
1973 gtk_tree_model_get (priv->header_model, &tmp_iter,
1974 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1977 /* Read the message & show it */
1978 if (!message_reader (window, priv, header, row_reference)) {
1981 gtk_tree_row_reference_free (row_reference);
1984 g_object_unref (header);
1990 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1992 ModestMsgViewWindowPrivate *priv = NULL;
1994 gboolean finished = FALSE;
1995 gboolean retval = FALSE;
1997 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1998 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2000 /* Return inmediatly if there is no header model */
2001 if (!priv->header_model || !priv->row_reference)
2004 path = gtk_tree_row_reference_get_path (priv->row_reference);
2005 while (!finished && gtk_tree_path_prev (path)) {
2009 gtk_tree_model_get_iter (priv->header_model, &iter, path);
2010 gtk_tree_model_get (priv->header_model, &iter,
2011 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2015 if (msg_is_visible (header, priv->is_outbox)) {
2016 GtkTreeRowReference *row_reference;
2017 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
2018 /* Read the message & show it */
2019 retval = message_reader (window, priv, header, row_reference);
2020 gtk_tree_row_reference_free (row_reference);
2024 g_object_unref (header);
2028 gtk_tree_path_free (path);
2033 view_msg_cb (ModestMailOperation *mail_op,
2040 ModestMsgViewWindow *self = NULL;
2041 ModestMsgViewWindowPrivate *priv = NULL;
2042 GtkTreeRowReference *row_reference = NULL;
2044 /* Unregister the header (it was registered before creating the mail operation) */
2045 modest_window_mgr_unregister_header (modest_runtime_get_window_mgr (), header);
2047 row_reference = (GtkTreeRowReference *) user_data;
2049 gtk_tree_row_reference_free (row_reference);
2050 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2052 /* Restore window title */
2053 update_window_title (self);
2054 g_object_unref (self);
2059 /* If there was any error */
2060 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
2061 gtk_tree_row_reference_free (row_reference);
2062 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2064 /* Restore window title */
2065 update_window_title (self);
2066 g_object_unref (self);
2071 /* Get the window */
2072 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
2073 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2074 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2076 /* Update the row reference */
2077 if (priv->row_reference != NULL) {
2078 gtk_tree_row_reference_free (priv->row_reference);
2079 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
2080 if (priv->next_row_reference != NULL) {
2081 gtk_tree_row_reference_free (priv->next_row_reference);
2083 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
2084 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox);
2087 /* Mark header as read */
2088 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
2089 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
2091 /* Set new message */
2092 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
2093 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2094 modest_msg_view_window_update_priority (self);
2095 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
2096 update_branding (MODEST_MSG_VIEW_WINDOW (self));
2097 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
2100 /* Set the new message uid of the window */
2101 if (priv->msg_uid) {
2102 g_free (priv->msg_uid);
2103 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
2106 /* Notify the observers */
2107 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
2108 0, priv->header_model, priv->row_reference);
2111 g_object_unref (self);
2112 gtk_tree_row_reference_free (row_reference);
2116 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
2118 ModestMsgViewWindowPrivate *priv;
2120 TnyFolderType folder_type;
2122 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2124 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
2126 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2130 folder = tny_msg_get_folder (msg);
2132 folder_type = modest_tny_folder_guess_folder_type (folder);
2133 g_object_unref (folder);
2135 g_object_unref (msg);
2143 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
2145 ModestMsgViewWindowPrivate *priv;
2146 TnyHeader *header = NULL;
2147 TnyHeaderFlags flags = 0;
2149 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2151 if (priv->header_model && priv->row_reference) {
2153 GtkTreePath *path = NULL;
2155 path = gtk_tree_row_reference_get_path (priv->row_reference);
2156 g_return_if_fail (path != NULL);
2157 gtk_tree_model_get_iter (priv->header_model,
2159 gtk_tree_row_reference_get_path (priv->row_reference));
2161 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
2163 gtk_tree_path_free (path);
2166 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2168 header = tny_msg_get_header (msg);
2169 g_object_unref (msg);
2174 flags = tny_header_get_flags (header);
2175 g_object_unref(G_OBJECT(header));
2178 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
2183 toolbar_resize (ModestMsgViewWindow *self)
2185 ModestMsgViewWindowPrivate *priv = NULL;
2186 ModestWindowPrivate *parent_priv = NULL;
2188 gint static_button_size;
2189 ModestWindowMgr *mgr;
2191 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2192 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2193 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2195 mgr = modest_runtime_get_window_mgr ();
2196 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?120:120;
2198 if (parent_priv->toolbar) {
2199 /* left size buttons */
2200 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
2201 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2202 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2203 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2204 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
2205 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2206 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2207 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2208 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
2209 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2210 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2211 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2212 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
2213 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
2214 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
2215 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
2217 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2218 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
2219 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2220 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2225 modest_msg_view_window_show_toolbar (ModestWindow *self,
2226 gboolean show_toolbar)
2228 ModestMsgViewWindowPrivate *priv = NULL;
2229 ModestWindowPrivate *parent_priv;
2231 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2232 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2234 /* Set optimized view status */
2235 priv->optimized_view = !show_toolbar;
2237 if (!parent_priv->toolbar) {
2238 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2240 gtk_toolbar_set_icon_size (GTK_TOOLBAR (parent_priv->toolbar), HILDON_ICON_SIZE_FINGER);
2241 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2243 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2244 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2245 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2248 hildon_window_add_toolbar (HILDON_WINDOW (self),
2249 GTK_TOOLBAR (parent_priv->toolbar));
2254 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2255 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2256 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2258 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2259 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2260 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), TRUE);
2262 set_progress_hint (MODEST_MSG_VIEW_WINDOW (self), FALSE);
2265 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2266 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2271 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2273 ModestMsgViewWindow *window)
2275 if (!GTK_WIDGET_VISIBLE (window))
2278 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2282 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2284 ModestMsgViewWindowPrivate *priv;
2286 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2287 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2289 return priv->progress_hint;
2293 observers_empty (ModestMsgViewWindow *self)
2296 ModestMsgViewWindowPrivate *priv;
2297 gboolean is_empty = TRUE;
2298 guint pending_ops = 0;
2300 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2301 tmp = priv->progress_widgets;
2303 /* Check all observers */
2304 while (tmp && is_empty) {
2305 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2306 is_empty = pending_ops == 0;
2308 tmp = g_slist_next(tmp);
2315 on_account_removed (TnyAccountStore *account_store,
2316 TnyAccount *account,
2319 /* Do nothing if it's a transport account, because we only
2320 show the messages of a store account */
2321 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2322 const gchar *parent_acc = NULL;
2323 const gchar *our_acc = NULL;
2325 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2326 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2328 /* Close this window if I'm showing a message of the removed account */
2329 if (our_acc && parent_acc && strcmp (parent_acc, our_acc) == 0)
2330 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2335 on_mail_operation_started (ModestMailOperation *mail_op,
2338 ModestMsgViewWindow *self;
2339 ModestMailOperationTypeOperation op_type;
2341 ModestMsgViewWindowPrivate *priv;
2342 GObject *source = NULL;
2344 self = MODEST_MSG_VIEW_WINDOW (user_data);
2345 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2346 op_type = modest_mail_operation_get_type_operation (mail_op);
2347 tmp = priv->progress_widgets;
2348 source = modest_mail_operation_get_source(mail_op);
2349 if (G_OBJECT (self) == source) {
2350 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2351 set_toolbar_transfer_mode(self);
2353 modest_progress_object_add_operation (
2354 MODEST_PROGRESS_OBJECT (tmp->data),
2356 tmp = g_slist_next (tmp);
2360 g_object_unref (source);
2364 on_mail_operation_finished (ModestMailOperation *mail_op,
2367 ModestMsgViewWindow *self;
2368 ModestMailOperationTypeOperation op_type;
2370 ModestMsgViewWindowPrivate *priv;
2372 self = MODEST_MSG_VIEW_WINDOW (user_data);
2373 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2374 op_type = modest_mail_operation_get_type_operation (mail_op);
2375 tmp = priv->progress_widgets;
2377 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2379 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2381 tmp = g_slist_next (tmp);
2384 /* If no more operations are being observed, NORMAL mode is enabled again */
2385 if (observers_empty (self)) {
2386 set_progress_hint (self, FALSE);
2390 /* Update dimming rules. We have to do this right here
2391 and not in view_msg_cb because at that point the
2392 transfer mode is still enabled so the dimming rule
2393 won't let the user delete the message that has been
2394 readed for example */
2395 check_dimming_rules_after_change (self);
2400 on_queue_changed (ModestMailOperationQueue *queue,
2401 ModestMailOperation *mail_op,
2402 ModestMailOperationQueueNotification type,
2403 ModestMsgViewWindow *self)
2405 ModestMsgViewWindowPrivate *priv;
2407 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2409 /* If this operations was created by another window, do nothing */
2410 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2413 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2414 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2416 "operation-started",
2417 G_CALLBACK (on_mail_operation_started),
2419 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2421 "operation-finished",
2422 G_CALLBACK (on_mail_operation_finished),
2424 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2425 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2427 "operation-started");
2428 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2430 "operation-finished");
2435 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2437 ModestMsgViewWindowPrivate *priv;
2438 TnyList *selected_attachments = NULL;
2440 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2441 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2443 /* In Hildon 2.2 as there's no selection we assume we have all attachments selected */
2444 selected_attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2446 return selected_attachments;
2450 ModestMsgViewWindow *self;
2452 } DecodeAsyncHelper;
2455 on_decode_to_stream_async_handler (TnyMimePart *mime_part,
2461 DecodeAsyncHelper *helper = (DecodeAsyncHelper *) user_data;
2463 /* It could happen that the window was closed */
2464 if (GTK_WIDGET_VISIBLE (helper->self))
2465 set_progress_hint (helper->self, FALSE);
2467 if (cancelled || err) {
2469 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2470 modest_platform_information_banner (NULL, NULL, msg);
2476 /* make the file read-only */
2477 g_chmod(helper->file_path, 0444);
2479 /* Activate the file */
2480 modest_platform_activate_file (helper->file_path, tny_mime_part_get_content_type (mime_part));
2484 g_object_unref (helper->self);
2485 g_free (helper->file_path);
2486 g_slice_free (DecodeAsyncHelper, helper);
2490 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window,
2491 TnyMimePart *mime_part)
2493 ModestMsgViewWindowPrivate *priv;
2494 const gchar *msg_uid;
2495 gchar *attachment_uid = NULL;
2496 gint attachment_index = 0;
2497 TnyList *attachments;
2499 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2500 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2501 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2503 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2504 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2505 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2506 g_object_unref (attachments);
2508 if (msg_uid && attachment_index >= 0) {
2509 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2512 if (mime_part == NULL) {
2513 gboolean error = FALSE;
2514 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2515 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2517 } else if (tny_list_get_length (selected_attachments) > 1) {
2518 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2522 iter = tny_list_create_iterator (selected_attachments);
2523 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2524 g_object_unref (iter);
2526 if (selected_attachments)
2527 g_object_unref (selected_attachments);
2532 g_object_ref (mime_part);
2535 if (tny_mime_part_is_purged (mime_part))
2538 if (!modest_tny_mime_part_is_msg (mime_part) && tny_mime_part_get_filename (mime_part)) {
2539 gchar *filepath = NULL;
2540 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2541 gboolean show_error_banner = FALSE;
2542 TnyFsStream *temp_stream = NULL;
2543 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2546 if (temp_stream != NULL) {
2547 DecodeAsyncHelper *helper;
2549 /* Activate progress hint */
2550 set_progress_hint (window, TRUE);
2552 helper = g_slice_new0 (DecodeAsyncHelper);
2553 helper->self = g_object_ref (window);
2554 helper->file_path = g_strdup (filepath);
2556 tny_mime_part_decode_to_stream_async (mime_part, TNY_STREAM (temp_stream),
2557 on_decode_to_stream_async_handler,
2560 g_object_unref (temp_stream);
2561 /* NOTE: files in the temporary area will be automatically
2562 * cleaned after some time if they are no longer in use */
2565 const gchar *content_type;
2566 /* the file may already exist but it isn't writable,
2567 * let's try to open it anyway */
2568 content_type = tny_mime_part_get_content_type (mime_part);
2569 modest_platform_activate_file (filepath, content_type);
2571 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2572 show_error_banner = TRUE;
2577 if (show_error_banner)
2578 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2579 } else if (!modest_tny_mime_part_is_msg (mime_part)) {
2580 ModestWindowMgr *mgr;
2581 ModestWindow *msg_win = NULL;
2582 TnyMsg *current_msg;
2586 current_msg = modest_msg_view_window_get_message (MODEST_MSG_VIEW_WINDOW (window));
2587 mgr = modest_runtime_get_window_mgr ();
2588 header = tny_msg_get_header (TNY_MSG (current_msg));
2589 found = modest_window_mgr_find_registered_message_uid (mgr,
2594 g_debug ("window for this body is already being created");
2597 /* it's not found, so create a new window for it */
2598 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2599 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2600 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2602 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2604 msg_win = modest_msg_view_window_new_with_other_body (TNY_MSG (current_msg), TNY_MIME_PART (mime_part),
2605 account, mailbox, attachment_uid);
2607 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2608 modest_window_get_zoom (MODEST_WINDOW (window)));
2609 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2610 gtk_widget_show_all (GTK_WIDGET (msg_win));
2612 gtk_widget_destroy (GTK_WIDGET (msg_win));
2614 g_object_unref (current_msg);
2616 /* message attachment */
2617 TnyHeader *header = NULL;
2618 ModestWindowMgr *mgr;
2619 ModestWindow *msg_win = NULL;
2622 header = tny_msg_get_header (TNY_MSG (mime_part));
2623 mgr = modest_runtime_get_window_mgr ();
2624 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2627 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2628 * thus, we don't do anything */
2629 g_debug ("window for is already being created");
2631 /* it's not found, so create a new window for it */
2632 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2633 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2634 const gchar *mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (window));
2636 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2637 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account,
2638 mailbox, attachment_uid);
2639 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2640 modest_window_get_zoom (MODEST_WINDOW (window)));
2641 if (modest_window_mgr_register_window (mgr, msg_win, MODEST_WINDOW (window)))
2642 gtk_widget_show_all (GTK_WIDGET (msg_win));
2644 gtk_widget_destroy (GTK_WIDGET (msg_win));
2650 g_free (attachment_uid);
2652 g_object_unref (mime_part);
2664 GnomeVFSResult result;
2667 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2668 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2669 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2670 static void save_mime_parts_to_file_with_checks (GtkWindow *parent, SaveMimePartInfo *info);
2673 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2677 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2678 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2679 g_free (pair->filename);
2680 g_object_unref (pair->part);
2681 g_slice_free (SaveMimePartPair, pair);
2683 g_list_free (info->pairs);
2686 g_slice_free (SaveMimePartInfo, info);
2691 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2693 if (info->pairs != NULL) {
2694 save_mime_part_to_file (info);
2696 /* This is a GDK lock because we are an idle callback and
2697 * hildon_banner_show_information is or does Gtk+ code */
2699 gdk_threads_enter (); /* CHECKED */
2700 save_mime_part_info_free (info, TRUE);
2701 if (info->result == GNOME_VFS_OK) {
2702 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2703 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
2704 gchar *msg = g_strdup_printf (_KR("cerm_device_memory_full"), "");
2705 modest_platform_information_banner (NULL, NULL, msg);
2708 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2710 gdk_threads_leave (); /* CHECKED */
2717 save_mime_part_to_file (SaveMimePartInfo *info)
2719 GnomeVFSHandle *handle;
2721 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2723 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2724 if (info->result == GNOME_VFS_OK) {
2725 GError *error = NULL;
2726 stream = tny_vfs_stream_new (handle);
2727 if (tny_mime_part_decode_to_stream (pair->part, stream, &error) < 0) {
2728 g_warning ("modest: could not save attachment %s: %d (%s)\n", pair->filename, error?error->code:-1, error?error->message:"Unknown error");
2730 if ((error->domain == TNY_ERROR_DOMAIN) &&
2731 (error->code == TNY_IO_ERROR_WRITE) &&
2732 (errno == ENOSPC)) {
2733 info->result = GNOME_VFS_ERROR_NO_SPACE;
2735 info->result = GNOME_VFS_ERROR_IO;
2738 g_object_unref (G_OBJECT (stream));
2739 g_object_unref (pair->part);
2740 g_slice_free (SaveMimePartPair, pair);
2741 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2743 g_warning ("Could not create save attachment %s: %s\n", pair->filename, gnome_vfs_result_to_string (info->result));
2744 save_mime_part_info_free (info, FALSE);
2747 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2752 save_mime_parts_to_file_with_checks (GtkWindow *parent,
2753 SaveMimePartInfo *info)
2755 gboolean is_ok = TRUE;
2756 gint replaced_files = 0;
2757 const GList *files = info->pairs;
2758 const GList *iter, *to_replace;
2760 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2761 SaveMimePartPair *pair = iter->data;
2762 if (modest_utils_file_exists (pair->filename)) {
2764 if (replaced_files == 1)
2768 if (replaced_files) {
2771 if (replaced_files == 1) {
2772 SaveMimePartPair *pair = to_replace->data;
2773 const gchar *basename = strrchr (pair->filename, G_DIR_SEPARATOR) + 1;
2774 gchar *escaped_basename, *message;
2776 escaped_basename = g_uri_unescape_string (basename, NULL);
2777 message = g_strdup_printf ("%s\n%s",
2778 _FM("docm_nc_replace_file"),
2779 (escaped_basename) ? escaped_basename : "");
2780 response = modest_platform_run_confirmation_dialog (parent, message);
2782 g_free (escaped_basename);
2784 response = modest_platform_run_confirmation_dialog (parent,
2785 _FM("docm_nc_replace_multiple"));
2787 if (response != GTK_RESPONSE_OK)
2792 save_mime_part_info_free (info, TRUE);
2794 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2800 save_attachments_response (GtkDialog *dialog,
2804 TnyList *mime_parts;
2806 GList *files_to_save = NULL;
2807 gchar *current_folder;
2809 mime_parts = TNY_LIST (user_data);
2811 if (arg1 != GTK_RESPONSE_OK)
2814 chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
2815 current_folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dialog));
2816 if (current_folder && current_folder != '\0') {
2818 modest_conf_set_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH,
2819 current_folder,&err);
2821 g_debug ("Error storing latest used folder: %s", err->message);
2825 g_free (current_folder);
2827 if (!modest_utils_folder_writable (chooser_uri)) {
2828 hildon_banner_show_information
2829 (NULL, NULL, _FM("sfil_ib_readonly_location"));
2833 iter = tny_list_create_iterator (mime_parts);
2834 while (!tny_iterator_is_done (iter)) {
2835 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2837 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
2838 !tny_mime_part_is_purged (mime_part) &&
2839 (tny_mime_part_get_filename (mime_part) != NULL)) {
2840 SaveMimePartPair *pair;
2842 pair = g_slice_new0 (SaveMimePartPair);
2844 if (tny_list_get_length (mime_parts) > 1) {
2846 gnome_vfs_escape_slashes (tny_mime_part_get_filename (mime_part));
2847 pair->filename = g_build_filename (chooser_uri, escaped, NULL);
2850 pair->filename = g_strdup (chooser_uri);
2852 pair->part = mime_part;
2853 files_to_save = g_list_prepend (files_to_save, pair);
2855 tny_iterator_next (iter);
2857 g_object_unref (iter);
2859 g_free (chooser_uri);
2861 if (files_to_save != NULL) {
2862 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2863 info->pairs = files_to_save;
2864 info->result = TRUE;
2865 save_mime_parts_to_file_with_checks ((GtkWindow *) dialog, info);
2869 /* Free and close the dialog */
2870 g_object_unref (mime_parts);
2871 gtk_widget_destroy (GTK_WIDGET (dialog));
2875 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window,
2876 TnyList *mime_parts)
2878 ModestMsgViewWindowPrivate *priv;
2879 GtkWidget *save_dialog = NULL;
2880 gchar *conf_folder = NULL;
2881 gchar *filename = NULL;
2882 gchar *save_multiple_str = NULL;
2884 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2885 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2887 if (mime_parts == NULL) {
2888 /* In Hildon 2.2 save and delete operate over all the attachments as there's no
2889 * selection available */
2890 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2891 if (mime_parts && !modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, FALSE)) {
2892 g_object_unref (mime_parts);
2895 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0) {
2897 g_object_unref (mime_parts);
2903 g_object_ref (mime_parts);
2906 /* prepare dialog */
2907 if (tny_list_get_length (mime_parts) == 1) {
2909 /* only one attachment selected */
2910 iter = tny_list_create_iterator (mime_parts);
2911 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2912 g_object_unref (iter);
2913 if (!modest_tny_mime_part_is_msg (mime_part) &&
2914 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
2915 !tny_mime_part_is_purged (mime_part)) {
2916 filename = g_strdup (tny_mime_part_get_filename (mime_part));
2918 /* TODO: show any error? */
2919 g_warning ("%s: Tried to save a non-file attachment", __FUNCTION__);
2920 g_object_unref (mime_parts);
2923 g_object_unref (mime_part);
2925 gint num = tny_list_get_length (mime_parts);
2926 save_multiple_str = g_strdup_printf (dngettext("hildon-fm",
2927 "sfil_va_number_of_objects_attachment",
2928 "sfil_va_number_of_objects_attachments",
2932 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2933 GTK_FILE_CHOOSER_ACTION_SAVE);
2936 conf_folder = modest_conf_get_string (modest_runtime_get_conf (), MODEST_CONF_LATEST_SAVE_ATTACHMENT_PATH, NULL);
2937 if (conf_folder && conf_folder[0] != '\0') {
2938 gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (save_dialog), conf_folder);
2941 /* Set the default folder to images folder */
2942 docs_folder = g_build_filename (g_getenv (MYDOCS_ENV), DOCS_FOLDER, NULL);
2943 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), docs_folder);
2944 g_free (docs_folder);
2946 g_free (conf_folder);
2950 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2955 /* if multiple, set multiple string */
2956 if (save_multiple_str) {
2957 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2958 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
2961 /* We must run this asynchronously, because the hildon dialog
2962 performs a gtk_dialog_run by itself which leads to gdk
2964 g_signal_connect (save_dialog, "response",
2965 G_CALLBACK (save_attachments_response), mime_parts);
2967 gtk_widget_show_all (save_dialog);
2971 show_remove_attachment_information (gpointer userdata)
2973 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2974 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2976 /* We're outside the main lock */
2977 gdk_threads_enter ();
2979 if (priv->remove_attachment_banner != NULL) {
2980 gtk_widget_destroy (priv->remove_attachment_banner);
2981 g_object_unref (priv->remove_attachment_banner);
2984 priv->remove_attachment_banner = g_object_ref (
2985 hildon_banner_show_animation (NULL, NULL, _("mcen_me_inbox_remove_attachments")));
2987 gdk_threads_leave ();
2993 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2995 ModestMsgViewWindowPrivate *priv;
2996 TnyList *mime_parts = NULL, *tmp;
2997 gchar *confirmation_message;
3003 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
3004 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3006 /* In hildon 2.2 we ignore the get_all flag as we always get all attachments. This is
3007 * because we don't have selection
3009 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
3011 /* Remove already purged messages from mime parts list. We use
3012 a copy of the list to remove items in the original one */
3013 tmp = tny_list_copy (mime_parts);
3014 iter = tny_list_create_iterator (tmp);
3015 while (!tny_iterator_is_done (iter)) {
3016 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
3017 if (tny_mime_part_is_purged (part))
3018 tny_list_remove (mime_parts, (GObject *) part);
3020 g_object_unref (part);
3021 tny_iterator_next (iter);
3023 g_object_unref (tmp);
3024 g_object_unref (iter);
3026 if (!modest_maemo_utils_select_attachments (GTK_WINDOW (window), mime_parts, TRUE) ||
3027 tny_list_get_length (mime_parts) == 0) {
3028 g_object_unref (mime_parts);
3032 n_attachments = tny_list_get_length (mime_parts);
3033 if (n_attachments == 1) {
3037 iter = tny_list_create_iterator (mime_parts);
3038 part = (TnyMimePart *) tny_iterator_get_current (iter);
3039 g_object_unref (iter);
3040 if (modest_tny_mime_part_is_msg (part)) {
3042 header = tny_msg_get_header (TNY_MSG (part));
3043 filename = tny_header_dup_subject (header);
3044 g_object_unref (header);
3045 if (filename == NULL)
3046 filename = g_strdup (_("mail_va_no_subject"));
3048 filename = g_strdup (tny_mime_part_get_filename (TNY_MIME_PART (part)));
3050 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
3052 g_object_unref (part);
3054 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
3055 "mcen_nc_purge_files_text",
3056 n_attachments), n_attachments);
3058 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
3059 confirmation_message);
3060 g_free (confirmation_message);
3062 if (response != GTK_RESPONSE_OK) {
3063 g_object_unref (mime_parts);
3067 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
3069 iter = tny_list_create_iterator (mime_parts);
3070 while (!tny_iterator_is_done (iter)) {
3073 part = (TnyMimePart *) tny_iterator_get_current (iter);
3074 tny_mime_part_set_purged (TNY_MIME_PART (part));
3075 g_object_unref (part);
3076 tny_iterator_next (iter);
3078 g_object_unref (iter);
3080 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3081 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
3082 tny_msg_rewrite_cache (msg);
3083 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
3084 g_object_unref (msg);
3085 update_branding (MODEST_MSG_VIEW_WINDOW (window));
3087 g_object_unref (mime_parts);
3089 if (priv->purge_timeout > 0) {
3090 g_source_remove (priv->purge_timeout);
3091 priv->purge_timeout = 0;
3094 if (priv->remove_attachment_banner) {
3095 gtk_widget_destroy (priv->remove_attachment_banner);
3096 g_object_unref (priv->remove_attachment_banner);
3097 priv->remove_attachment_banner = NULL;
3103 update_window_title (ModestMsgViewWindow *window)
3105 ModestMsgViewWindowPrivate *priv;
3107 TnyHeader *header = NULL;
3108 gchar *subject = NULL;
3110 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3112 /* Note that if the window is closed while we're retrieving
3113 the message, this widget could de deleted */
3114 if (!priv->msg_view)
3117 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3119 if (priv->other_body) {
3122 description = modest_tny_mime_part_get_header_value (priv->other_body, "Content-Description");
3124 g_strstrip (description);
3125 subject = description;
3127 } else if (msg != NULL) {
3128 header = tny_msg_get_header (msg);
3129 subject = tny_header_dup_subject (header);
3130 g_object_unref (header);
3131 g_object_unref (msg);
3134 if ((subject == NULL)||(subject[0] == '\0')) {
3136 subject = g_strdup (_("mail_va_no_subject"));
3139 gtk_window_set_title (GTK_WINDOW (window), subject);
3144 on_move_focus (GtkWidget *widget,
3145 GtkDirectionType direction,
3148 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");
3152 fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri)
3154 GnomeVFSResult result;
3155 GnomeVFSHandle *handle = NULL;
3156 GnomeVFSFileInfo *info = NULL;
3159 result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
3160 if (result != GNOME_VFS_OK) {
3165 info = gnome_vfs_file_info_new ();
3166 result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT);
3167 if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) {
3168 /* We put a "safe" default size for going to cache */
3169 *expected_size = (300*1024);
3171 *expected_size = info->size;
3173 gnome_vfs_file_info_unref (info);
3175 stream = tny_vfs_stream_new (handle);
3184 TnyStream *output_stream;
3185 GtkWidget *msg_view;
3190 on_fetch_image_idle_refresh_view (gpointer userdata)
3193 FetchImageData *fidata = (FetchImageData *) userdata;
3195 gdk_threads_enter ();
3196 if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) {
3197 ModestMsgViewWindowPrivate *priv;
3199 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (fidata->window);
3200 priv->fetching_images--;
3201 gtk_widget_queue_draw (fidata->msg_view);
3202 update_progress_hint (MODEST_MSG_VIEW_WINDOW (fidata->window));
3204 gdk_threads_leave ();
3206 g_object_unref (fidata->msg_view);
3207 g_object_unref (fidata->window);
3208 g_slice_free (FetchImageData, fidata);
3213 on_fetch_image_thread (gpointer userdata)
3215 FetchImageData *fidata = (FetchImageData *) userdata;
3216 TnyStreamCache *cache;
3217 TnyStream *cache_stream;
3219 cache = modest_runtime_get_images_cache ();
3221 tny_stream_cache_get_stream (cache,
3223 (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream,
3224 (gpointer) fidata->uri);
3225 g_free (fidata->cache_id);
3226 g_free (fidata->uri);
3228 if (cache_stream != NULL) {
3231 while (G_LIKELY (!tny_stream_is_eos (cache_stream))) {
3234 nb_read = tny_stream_read (cache_stream, buffer, sizeof (buffer));
3235 if (G_UNLIKELY (nb_read < 0)) {
3237 } else if (G_LIKELY (nb_read > 0)) {
3238 gssize nb_written = 0;
3240 while (G_UNLIKELY (nb_written < nb_read)) {
3243 len = tny_stream_write (fidata->output_stream, buffer + nb_written,
3244 nb_read - nb_written);
3245 if (G_UNLIKELY (len < 0))
3251 tny_stream_close (cache_stream);
3252 g_object_unref (cache_stream);
3255 tny_stream_close (fidata->output_stream);
3256 g_object_unref (fidata->output_stream);
3258 g_idle_add (on_fetch_image_idle_refresh_view, fidata);
3264 on_fetch_image (ModestMsgView *msgview,
3267 ModestMsgViewWindow *window)
3269 const gchar *current_account;
3270 ModestMsgViewWindowPrivate *priv;
3271 FetchImageData *fidata;
3273 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
3275 current_account = modest_window_get_active_account (MODEST_WINDOW (window));
3277 fidata = g_slice_new0 (FetchImageData);
3278 fidata->msg_view = g_object_ref (msgview);
3279 fidata->window = g_object_ref (window);
3280 fidata->uri = g_strdup (uri);
3281 fidata->cache_id = modest_images_cache_get_id (current_account, uri);
3282 fidata->output_stream = g_object_ref (stream);
3284 priv->fetching_images++;
3285 if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) {
3286 g_object_unref (fidata->output_stream);
3287 g_free (fidata->cache_id);
3288 g_free (fidata->uri);
3289 g_object_unref (fidata->msg_view);
3290 g_slice_free (FetchImageData, fidata);
3291 tny_stream_close (stream);
3292 priv->fetching_images--;
3293 update_progress_hint (window);
3296 update_progress_hint (window);
3302 setup_menu (ModestMsgViewWindow *self)
3304 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW(self));
3306 /* Settings menu buttons */
3307 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_replytoall"), NULL,
3308 APP_MENU_CALLBACK (modest_ui_actions_on_reply_all),
3309 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3310 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_forward"), "<Control>d",
3311 APP_MENU_CALLBACK (modest_ui_actions_on_forward),
3312 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_reply_msg));
3314 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_read"), NULL,
3315 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_read),
3316 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_read_msg_in_view));
3317 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_mark_as_unread"), NULL,
3318 APP_MENU_CALLBACK (modest_ui_actions_on_mark_as_unread),
3319 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_mark_as_unread_msg_in_view));
3321 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_save_attachments"), NULL,
3322 APP_MENU_CALLBACK (modest_ui_actions_save_attachments),
3323 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_save_attachments));
3324 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_remove_attachments"), NULL,
3325 APP_MENU_CALLBACK (modest_ui_actions_remove_attachments),
3326 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_remove_attachments));
3328 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_new_message"), "<Control>n",
3329 APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
3330 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
3331 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_addtocontacts"), NULL,
3332 APP_MENU_CALLBACK (modest_ui_actions_add_to_contacts),
3333 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_add_to_contacts));
3335 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mail_bd_external_images"), NULL,
3336 APP_MENU_CALLBACK (modest_ui_actions_on_fetch_images),
3337 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_fetch_images));
3338 modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_ti_message_properties"), NULL,
3339 APP_MENU_CALLBACK (modest_ui_actions_on_details),
3340 MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
3344 modest_msg_view_window_add_to_contacts (ModestMsgViewWindow *self)
3346 ModestMsgViewWindowPrivate *priv;
3347 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3348 GSList *recipients = NULL;
3350 gboolean contacts_to_add = FALSE;
3352 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
3356 header = modest_msg_view_window_get_header (self);
3359 recipients = modest_tny_msg_header_get_all_recipients_list (header);
3360 g_object_unref (header);
3362 recipients = modest_tny_msg_get_all_recipients_list (msg);
3363 g_object_unref (msg);
3366 if (recipients != NULL) {
3367 GtkWidget *picker_dialog;
3368 GtkWidget *selector;
3370 gchar *selected = NULL;
3372 selector = hildon_touch_selector_new_text ();
3373 g_object_ref (selector);
3375 for (node = recipients; node != NULL; node = g_slist_next (node)) {
3376 if (!modest_address_book_has_address ((const gchar *) node->data)) {
3377 hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector),
3378 (const gchar *) node->data);
3379 contacts_to_add = TRUE;
3383 if (contacts_to_add) {
3386 picker_dialog = hildon_picker_dialog_new (GTK_WINDOW (self));
3387 gtk_window_set_title (GTK_WINDOW (picker_dialog), _("mcen_me_viewer_addtocontacts"));
3389 hildon_picker_dialog_set_selector (HILDON_PICKER_DIALOG (picker_dialog),
3390 HILDON_TOUCH_SELECTOR (selector));
3392 picker_result = gtk_dialog_run (GTK_DIALOG (picker_dialog));
3394 if (picker_result == GTK_RESPONSE_OK) {
3395 selected = hildon_touch_selector_get_current_text (HILDON_TOUCH_SELECTOR (selector));
3397 gtk_widget_destroy (picker_dialog);
3400 modest_address_book_add_address (selected);
3405 g_object_unref (selector);
3410 if (recipients) {g_slist_foreach (recipients, (GFunc) g_free, NULL); g_slist_free (recipients);}
3414 _modest_msg_view_window_map_event (GtkWidget *widget,
3418 ModestMsgViewWindow *self = (ModestMsgViewWindow *) userdata;
3420 update_progress_hint (self);
3426 modest_msg_view_window_fetch_images (ModestMsgViewWindow *self)
3428 ModestMsgViewWindowPrivate *priv;
3429 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3431 modest_msg_view_request_fetch_images (MODEST_MSG_VIEW (priv->msg_view));
3435 modest_msg_view_window_has_blocked_external_images (ModestMsgViewWindow *self)
3437 ModestMsgViewWindowPrivate *priv;
3438 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3440 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
3442 return modest_msg_view_has_blocked_external_images (MODEST_MSG_VIEW (priv->msg_view));
3446 modest_msg_view_window_reload (ModestMsgViewWindow *self)
3448 ModestMsgViewWindowPrivate *priv;
3451 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
3453 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3454 header = modest_msg_view_window_get_header (MODEST_MSG_VIEW_WINDOW (self));
3456 if (!message_reader (self, priv, header, priv->row_reference)) {
3457 g_warning ("Shouldn't happen, trying to reload a message failed");
3460 g_object_unref (header);
3464 update_branding (ModestMsgViewWindow *self)
3466 const gchar *account;
3467 const gchar *mailbox;
3468 ModestAccountMgr *mgr;
3469 ModestProtocol *protocol = NULL;
3470 gchar *service_name = NULL;
3471 const GdkPixbuf *service_icon = NULL;
3472 ModestMsgViewWindowPrivate *priv;
3474 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
3476 account = modest_window_get_active_account (MODEST_WINDOW (self));
3477 mailbox = modest_window_get_active_mailbox (MODEST_WINDOW (self));
3479 mgr = modest_runtime_get_account_mgr ();
3481 if (modest_account_mgr_account_is_multimailbox (mgr, account, &protocol)) {
3482 if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
3483 service_name = modest_account_protocol_get_service_name (MODEST_ACCOUNT_PROTOCOL (protocol),
3485 service_icon = modest_account_protocol_get_service_icon (MODEST_ACCOUNT_PROTOCOL (protocol),
3486 account, mailbox, MODEST_ICON_SIZE_SMALL);
3490 modest_msg_view_set_branding (MODEST_MSG_VIEW (priv->msg_view), service_name, service_icon);
3491 g_free (service_name);