1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include "modest-marshal.h"
37 #include "modest-platform.h"
38 #include <modest-maemo-utils.h>
39 #include <modest-tny-msg.h>
40 #include <modest-msg-view-window.h>
41 #include <modest-attachments-view.h>
42 #include <modest-main-window-ui.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-runtime.h>
46 #include <modest-window-priv.h>
47 #include <modest-tny-folder.h>
48 #include <modest-text-utils.h>
49 #include <modest-account-mgr-helpers.h>
50 #include "modest-progress-bar-widget.h"
51 #include "modest-defs.h"
52 #include "modest-hildon-includes.h"
53 #include <gtkhtml/gtkhtml-search.h>
54 #include "modest-ui-dimming-manager.h"
55 #include <gdk/gdkkeysyms.h>
56 #include <modest-tny-account.h>
58 #define DEFAULT_FOLDER "MyDocs/.documents"
60 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
61 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
62 static void modest_msg_view_window_finalize (GObject *obj);
63 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
65 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
66 ModestMsgViewWindow *obj);
67 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
68 ModestMsgViewWindow *obj);
70 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
71 static void modest_msg_view_window_set_zoom (ModestWindow *window,
73 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
74 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
75 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
76 static gboolean modest_msg_view_window_key_release_event (GtkWidget *window,
79 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
80 GdkEventWindowState *event,
82 static void modest_msg_view_window_scroll_up (ModestWindow *window);
83 static void modest_msg_view_window_scroll_down (ModestWindow *window);
84 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
86 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
87 gboolean show_toolbar);
89 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
91 ModestMsgViewWindow *window);
92 void modest_msg_view_window_on_row_changed(
93 GtkTreeModel *header_model,
96 ModestMsgViewWindow *window);
98 void modest_msg_view_window_on_row_deleted(
99 GtkTreeModel *header_model,
101 ModestMsgViewWindow *window);
103 void modest_msg_view_window_on_row_inserted(
104 GtkTreeModel *header_model,
107 ModestMsgViewWindow *window);
109 void modest_msg_view_window_on_row_reordered(
110 GtkTreeModel *header_model,
114 ModestMsgViewWindow *window);
116 static void cancel_progressbar (GtkToolButton *toolbutton,
117 ModestMsgViewWindow *self);
119 static void on_queue_changed (ModestMailOperationQueue *queue,
120 ModestMailOperation *mail_op,
121 ModestMailOperationQueueNotification type,
122 ModestMsgViewWindow *self);
124 static void on_account_removed (TnyAccountStore *account_store,
128 static void view_msg_cb (ModestMailOperation *mail_op,
133 static void set_toolbar_mode (ModestMsgViewWindow *self,
134 ModestToolBarModes mode);
136 static void update_window_title (ModestMsgViewWindow *window);
138 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
141 /* list my signals */
147 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
148 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
149 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
152 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
153 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
154 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
155 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
156 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
157 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
158 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
161 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
162 struct _ModestMsgViewWindowPrivate {
165 GtkWidget *main_scroll;
166 GtkWidget *find_toolbar;
169 /* Progress observers */
170 GtkWidget *progress_bar;
171 GSList *progress_widgets;
174 GtkWidget *progress_toolitem;
175 GtkWidget *cancel_toolitem;
176 GtkWidget *prev_toolitem;
177 GtkWidget *next_toolitem;
178 ModestToolBarModes current_toolbar_mode;
180 /* Optimized view enabled */
181 gboolean optimized_view;
183 /* A reference to the @model of the header view
184 * to allow selecting previous/next messages,
185 * if the message is currently selected in the header view.
187 GtkTreeModel *header_model;
188 GtkTreeRowReference *row_reference;
189 GtkTreeRowReference *next_row_reference;
191 guint clipboard_change_handler;
192 guint queue_change_handler;
193 guint account_removed_handler;
196 GtkWidget *remove_attachment_banner;
198 guint progress_bar_timeout;
203 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
204 MODEST_TYPE_MSG_VIEW_WINDOW, \
205 ModestMsgViewWindowPrivate))
207 static GtkWindowClass *parent_class = NULL;
209 /* uncomment the following if you have defined any signals */
210 static guint signals[LAST_SIGNAL] = {0};
213 modest_msg_view_window_get_type (void)
215 static GType my_type = 0;
217 static const GTypeInfo my_info = {
218 sizeof(ModestMsgViewWindowClass),
219 NULL, /* base init */
220 NULL, /* base finalize */
221 (GClassInitFunc) modest_msg_view_window_class_init,
222 NULL, /* class finalize */
223 NULL, /* class data */
224 sizeof(ModestMsgViewWindow),
226 (GInstanceInitFunc) modest_msg_view_window_init,
229 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
230 "ModestMsgViewWindow",
237 save_state (ModestWindow *self)
239 modest_widget_memory_save (modest_runtime_get_conf (),
241 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
246 restore_settings (ModestMsgViewWindow *self)
248 modest_widget_memory_restore (modest_runtime_get_conf (),
250 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
254 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
256 GObjectClass *gobject_class;
257 ModestWindowClass *modest_window_class;
258 gobject_class = (GObjectClass*) klass;
259 modest_window_class = (ModestWindowClass *) klass;
261 parent_class = g_type_class_peek_parent (klass);
262 gobject_class->finalize = modest_msg_view_window_finalize;
264 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
265 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
266 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
267 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
268 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
269 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
271 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
273 modest_window_class->save_state_func = save_state;
275 signals[MSG_CHANGED_SIGNAL] =
276 g_signal_new ("msg-changed",
277 G_TYPE_FROM_CLASS (gobject_class),
279 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
281 modest_marshal_VOID__POINTER_POINTER,
282 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
286 modest_msg_view_window_init (ModestMsgViewWindow *obj)
288 ModestMsgViewWindowPrivate *priv;
289 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
291 priv->msg_view = NULL;
292 priv->header_model = NULL;
293 priv->clipboard_change_handler = 0;
294 priv->queue_change_handler = 0;
295 priv->account_removed_handler = 0;
296 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
298 priv->optimized_view = FALSE;
299 priv->progress_bar_timeout = 0;
300 priv->purge_timeout = 0;
301 priv->remove_attachment_banner = NULL;
302 priv->msg_uid = NULL;
307 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
309 ModestMsgViewWindowPrivate *priv = NULL;
311 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
313 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
315 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
317 if (priv->progress_bar_timeout > 0) {
318 g_source_remove (priv->progress_bar_timeout);
319 priv->progress_bar_timeout = 0;
326 set_toolbar_mode (ModestMsgViewWindow *self,
327 ModestToolBarModes mode)
329 ModestWindowPrivate *parent_priv;
330 ModestMsgViewWindowPrivate *priv;
331 /* GtkWidget *widget = NULL; */
333 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
335 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
336 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
338 /* Sets current toolbar mode */
339 priv->current_toolbar_mode = mode;
341 /* Update toolbar dimming state */
342 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
345 case TOOLBAR_MODE_NORMAL:
346 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
347 /* gtk_action_set_sensitive (widget, TRUE); */
348 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
349 /* gtk_action_set_sensitive (widget, TRUE); */
350 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
351 /* gtk_action_set_sensitive (widget, TRUE); */
352 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
353 /* gtk_action_set_sensitive (widget, TRUE); */
355 if (priv->prev_toolitem)
356 gtk_widget_show (priv->prev_toolitem);
358 if (priv->next_toolitem)
359 gtk_widget_show (priv->next_toolitem);
361 if (priv->progress_toolitem)
362 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
363 if (priv->progress_bar)
364 gtk_widget_hide (priv->progress_bar);
366 if (priv->cancel_toolitem)
367 gtk_widget_hide (priv->cancel_toolitem);
369 /* Hide toolbar if optimized view is enabled */
370 if (priv->optimized_view) {
371 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
372 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
376 case TOOLBAR_MODE_TRANSFER:
377 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
378 /* gtk_action_set_sensitive (widget, FALSE); */
379 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
380 /* gtk_action_set_sensitive (widget, FALSE); */
381 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
382 /* gtk_action_set_sensitive (widget, FALSE); */
383 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
384 /* gtk_action_set_sensitive (widget, FALSE); */
386 if (priv->prev_toolitem)
387 gtk_widget_hide (priv->prev_toolitem);
389 if (priv->next_toolitem)
390 gtk_widget_hide (priv->next_toolitem);
392 if (priv->progress_toolitem)
393 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
394 if (priv->progress_bar)
395 gtk_widget_show (priv->progress_bar);
397 if (priv->cancel_toolitem)
398 gtk_widget_show (priv->cancel_toolitem);
400 /* Show toolbar if it's hiden (optimized view ) */
401 if (priv->optimized_view) {
402 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
403 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
408 g_return_if_reached ();
415 menubar_to_menu (GtkUIManager *ui_manager)
417 GtkWidget *main_menu;
421 /* Create new main menu */
422 main_menu = gtk_menu_new();
424 /* Get the menubar from the UI manager */
425 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
427 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
431 menu = GTK_WIDGET (iter->data);
432 gtk_widget_reparent(menu, main_menu);
434 iter = g_list_next (iter);
440 init_window (ModestMsgViewWindow *obj, TnyMsg *msg)
442 GtkWidget *main_vbox;
443 ModestMsgViewWindowPrivate *priv;
444 ModestWindowPrivate *parent_priv;
446 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
447 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
449 priv->msg_view = modest_msg_view_new (msg);
450 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
451 main_vbox = gtk_vbox_new (FALSE, 6);
454 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
455 gtk_widget_show_all (GTK_WIDGET(parent_priv->menubar));
456 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
458 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
459 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
460 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
461 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
463 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
464 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
465 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
467 priv->find_toolbar = hildon_find_toolbar_new (NULL);
468 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
469 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
470 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
471 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
473 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);
474 gtk_widget_show_all (GTK_WIDGET(main_vbox));
478 modest_msg_view_window_disconnect_signals (ModestWindow *self)
480 ModestMsgViewWindowPrivate *priv;
482 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
484 if (g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
485 priv->clipboard_change_handler))
486 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
487 priv->clipboard_change_handler);
489 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
490 priv->queue_change_handler))
491 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
492 priv->queue_change_handler);
494 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
495 priv->account_removed_handler))
496 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
497 priv->account_removed_handler);
501 modest_msg_view_window_finalize (GObject *obj)
503 ModestMsgViewWindowPrivate *priv;
505 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
507 /* Sanity check: shouldn't be needed, the window mgr should
508 call this function before */
509 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
511 if (priv->header_model != NULL) {
512 g_object_unref (priv->header_model);
513 priv->header_model = NULL;
516 if (priv->progress_bar_timeout > 0) {
517 g_source_remove (priv->progress_bar_timeout);
518 priv->progress_bar_timeout = 0;
521 if (priv->remove_attachment_banner) {
522 gtk_widget_destroy (priv->remove_attachment_banner);
523 g_object_unref (priv->remove_attachment_banner);
524 priv->remove_attachment_banner = NULL;
527 if (priv->purge_timeout > 0) {
528 g_source_remove (priv->purge_timeout);
529 priv->purge_timeout = 0;
532 if (priv->row_reference) {
533 gtk_tree_row_reference_free (priv->row_reference);
534 priv->row_reference = NULL;
537 if (priv->next_row_reference) {
538 gtk_tree_row_reference_free (priv->next_row_reference);
539 priv->next_row_reference = NULL;
543 g_free (priv->msg_uid);
544 priv->msg_uid = NULL;
547 G_OBJECT_CLASS(parent_class)->finalize (obj);
551 select_next_valid_row (GtkTreeModel *model,
552 GtkTreeRowReference **row_reference,
555 GtkTreeIter tmp_iter;
556 GtkTreePath *path, *next;
557 gboolean retval = FALSE;
559 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
561 path = gtk_tree_row_reference_get_path (*row_reference);
562 gtk_tree_model_get_iter (model, &tmp_iter, path);
563 gtk_tree_row_reference_free (*row_reference);
564 *row_reference = NULL;
566 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
567 next = gtk_tree_model_get_path (model, &tmp_iter);
568 *row_reference = gtk_tree_row_reference_new (model, next);
570 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
571 next = gtk_tree_model_get_path (model, &tmp_iter);
573 /* Ensure that we are not selecting the same */
574 if (gtk_tree_path_compare (path, next) != 0) {
575 *row_reference = gtk_tree_row_reference_new (model, next);
581 gtk_tree_path_free (path);
587 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
588 const gchar *modest_account_name,
589 const gchar *msg_uid,
591 GtkTreeRowReference *row_reference)
593 ModestMsgViewWindow *window = NULL;
594 ModestMsgViewWindowPrivate *priv = NULL;
596 window = MODEST_MSG_VIEW_WINDOW(modest_msg_view_window_new (msg, modest_account_name, msg_uid));
597 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
599 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
601 g_object_ref (model);
602 priv->header_model = model;
603 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
604 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
605 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
607 g_signal_connect (GTK_TREE_MODEL(model), "row-changed",
608 G_CALLBACK (modest_msg_view_window_on_row_changed),
610 g_signal_connect (GTK_TREE_MODEL(model), "row-deleted",
611 G_CALLBACK (modest_msg_view_window_on_row_deleted),
613 g_signal_connect (GTK_TREE_MODEL(model), "row-inserted",
614 G_CALLBACK (modest_msg_view_window_on_row_inserted),
616 g_signal_connect (GTK_TREE_MODEL(model), "rows-reordered",
617 G_CALLBACK (modest_msg_view_window_on_row_reordered),
620 modest_msg_view_window_update_priority (window);
622 /* Check toolbar dimming rules */
623 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
625 return MODEST_WINDOW(window);
629 modest_msg_view_window_new (TnyMsg *msg,
630 const gchar *modest_account_name,
631 const gchar *msg_uid)
633 ModestMsgViewWindow *self = NULL;
635 ModestMsgViewWindowPrivate *priv = NULL;
636 ModestWindowPrivate *parent_priv = NULL;
637 ModestDimmingRulesGroup *menu_rules_group = NULL;
638 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
639 GtkActionGroup *action_group = NULL;
640 GError *error = NULL;
641 GdkPixbuf *window_icon;
643 g_return_val_if_fail (msg, NULL);
645 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
646 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
647 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
648 self = MODEST_MSG_VIEW_WINDOW (obj);
650 priv->msg_uid = g_strdup (msg_uid);
652 parent_priv->ui_manager = gtk_ui_manager_new();
653 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
655 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
656 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
658 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
659 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
661 /* Add common actions */
662 gtk_action_group_add_actions (action_group,
663 modest_action_entries,
664 G_N_ELEMENTS (modest_action_entries),
666 gtk_action_group_add_toggle_actions (action_group,
667 modest_toggle_action_entries,
668 G_N_ELEMENTS (modest_toggle_action_entries),
670 gtk_action_group_add_toggle_actions (action_group,
671 msg_view_toggle_action_entries,
672 G_N_ELEMENTS (msg_view_toggle_action_entries),
674 gtk_action_group_add_radio_actions (action_group,
675 msg_view_zoom_action_entries,
676 G_N_ELEMENTS (msg_view_zoom_action_entries),
678 G_CALLBACK (modest_ui_actions_on_change_zoom),
681 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
682 g_object_unref (action_group);
684 /* Load the UI definition */
685 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
688 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
689 g_error_free (error);
694 /* Add common dimming rules */
695 modest_dimming_rules_group_add_rules (menu_rules_group,
696 modest_msg_view_menu_dimming_entries,
697 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
699 modest_dimming_rules_group_add_rules (toolbar_rules_group,
700 modest_msg_view_toolbar_dimming_entries,
701 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
704 /* Insert dimming rules group for this window */
705 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
706 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
707 g_object_unref (menu_rules_group);
708 g_object_unref (toolbar_rules_group);
710 /* Add accelerators */
711 gtk_window_add_accel_group (GTK_WINDOW (obj),
712 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
715 init_window (MODEST_MSG_VIEW_WINDOW(obj), msg);
716 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
718 /* Set window icon */
719 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
721 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
722 g_object_unref (window_icon);
725 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
727 g_signal_connect (G_OBJECT(priv->msg_view), "link_clicked",
728 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
729 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
730 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
731 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
732 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
733 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
734 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
735 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
736 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
738 g_signal_connect (G_OBJECT (obj), "key-release-event",
739 G_CALLBACK (modest_msg_view_window_key_release_event),
742 g_signal_connect (G_OBJECT (obj), "window-state-event",
743 G_CALLBACK (modest_msg_view_window_window_state_event),
746 /* Mail Operation Queue */
747 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
749 G_CALLBACK (on_queue_changed),
752 /* Account manager */
753 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
755 G_CALLBACK(on_account_removed),
758 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
760 priv->last_search = NULL;
762 /* Init the clipboard actions dim status */
763 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
765 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
767 /* Check toolbar dimming rules */
768 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
770 return MODEST_WINDOW(obj);
773 void modest_msg_view_window_on_row_changed(
774 GtkTreeModel *header_model,
777 ModestMsgViewWindow *window){
778 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
781 void modest_msg_view_window_on_row_deleted(
782 GtkTreeModel *header_model,
784 ModestMsgViewWindow *window){
785 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
788 void modest_msg_view_window_on_row_inserted(
789 GtkTreeModel *header_model,
792 ModestMsgViewWindow *window){
793 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
796 void modest_msg_view_window_on_row_reordered(
797 GtkTreeModel *header_model,
801 ModestMsgViewWindow *window){
802 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
806 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
808 ModestMsgViewWindowPrivate *priv= NULL;
810 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
811 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
813 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
817 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
819 ModestMsgViewWindowPrivate *priv= NULL;
821 TnyHeader *header = NULL;
822 GtkTreePath *path = NULL;
825 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
826 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
828 /* If the message ws not obtained from a treemodel,
829 * for instance if it was opened directly by the search UI:
831 if (priv->header_model == NULL) {
832 msg = modest_msg_view_window_get_message (self);
833 header = tny_msg_get_header (msg);
834 g_object_unref (msg);
838 /* Get iter of the currently selected message in the header view: */
839 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
840 * instead of sometimes retrieving it from the header view?
841 * Then we wouldn't be dependent on the message actually still being selected
842 * in the header view. murrayc. */
843 path = gtk_tree_row_reference_get_path (priv->row_reference);
844 g_return_val_if_fail (path != NULL, NULL);
845 gtk_tree_model_get_iter (priv->header_model,
849 /* Get current message header */
850 gtk_tree_model_get (priv->header_model, &iter,
851 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
854 gtk_tree_path_free (path);
859 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
861 ModestMsgView *msg_view;
862 ModestMsgViewWindowPrivate *priv;
864 g_return_val_if_fail (self, NULL);
866 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
868 msg_view = MODEST_MSG_VIEW (priv->msg_view);
870 return modest_msg_view_get_message (msg_view);
874 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
876 ModestMsgViewWindowPrivate *priv;
878 g_return_val_if_fail (self, NULL);
880 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
882 return (const gchar*) priv->msg_uid;
886 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
889 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
890 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
891 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
895 is_active = gtk_toggle_action_get_active (toggle);
898 gtk_widget_show (priv->find_toolbar);
899 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
901 gtk_widget_hide (priv->find_toolbar);
904 /* update the toggle buttons status */
905 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
906 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
907 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
908 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
913 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
914 ModestMsgViewWindow *obj)
916 GtkToggleAction *toggle;
917 ModestWindowPrivate *parent_priv;
918 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
920 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
921 gtk_toggle_action_set_active (toggle, FALSE);
925 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
926 ModestMsgViewWindow *obj)
928 gchar *current_search;
929 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
931 if (modest_msg_view_get_message_is_empty (MODEST_MSG_VIEW (priv->msg_view))) {
932 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
936 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
938 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
939 g_free (current_search);
940 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
944 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
946 g_free (priv->last_search);
947 priv->last_search = g_strdup (current_search);
948 result = modest_msg_view_search (MODEST_MSG_VIEW (priv->msg_view),
951 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
952 g_free (priv->last_search);
953 priv->last_search = NULL;
956 if (!modest_msg_view_search_next (MODEST_MSG_VIEW (priv->msg_view))) {
957 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
958 g_free (priv->last_search);
959 priv->last_search = NULL;
963 g_free (current_search);
968 modest_msg_view_window_set_zoom (ModestWindow *window,
971 ModestMsgViewWindowPrivate *priv;
973 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
975 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
976 modest_msg_view_set_zoom (MODEST_MSG_VIEW (priv->msg_view), zoom);
980 modest_msg_view_window_get_zoom (ModestWindow *window)
982 ModestMsgViewWindowPrivate *priv;
984 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
986 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
987 return modest_msg_view_get_zoom (MODEST_MSG_VIEW (priv->msg_view));
991 modest_msg_view_window_zoom_plus (ModestWindow *window)
993 ModestWindowPrivate *parent_priv;
994 GtkRadioAction *zoom_radio_action;
995 GSList *group, *node;
997 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
998 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
999 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1001 group = gtk_radio_action_get_group (zoom_radio_action);
1003 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1004 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1008 for (node = group; node != NULL; node = g_slist_next (node)) {
1009 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1010 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1018 modest_msg_view_window_zoom_minus (ModestWindow *window)
1020 ModestWindowPrivate *parent_priv;
1021 GtkRadioAction *zoom_radio_action;
1022 GSList *group, *node;
1024 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1025 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1026 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1028 group = gtk_radio_action_get_group (zoom_radio_action);
1030 for (node = group; node != NULL; node = g_slist_next (node)) {
1031 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1032 if (node->next != NULL) {
1033 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1036 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1046 modest_msg_view_window_key_release_event (GtkWidget *window,
1050 if (event->type == GDK_KEY_RELEASE) {
1051 switch (event->keyval) {
1053 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1057 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1070 modest_msg_view_window_scroll_up (ModestWindow *window)
1072 ModestMsgViewWindowPrivate *priv;
1073 gboolean return_value;
1075 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1076 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1080 modest_msg_view_window_scroll_down (ModestWindow *window)
1082 ModestMsgViewWindowPrivate *priv;
1083 gboolean return_value;
1085 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1086 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1090 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1093 ModestMsgViewWindowPrivate *priv;
1094 GtkTreeIter tmp_iter;
1095 gboolean is_last_selected;
1097 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1098 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1100 /*if no model (so no rows at all), then virtually we are the last*/
1101 if (!priv->header_model)
1104 path = gtk_tree_row_reference_get_path (priv->row_reference);
1108 is_last_selected = TRUE;
1109 while (is_last_selected) {
1111 gtk_tree_path_next (path);
1112 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1114 gtk_tree_model_get (priv->header_model, &tmp_iter,
1115 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1117 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1118 is_last_selected = FALSE;
1120 gtk_tree_path_free (path);
1121 return is_last_selected;
1125 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1127 ModestMsgViewWindowPrivate *priv;
1129 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1130 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1132 return priv->header_model != NULL;
1136 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1139 ModestMsgViewWindowPrivate *priv;
1140 gboolean is_first_selected;
1141 GtkTreeIter tmp_iter;
1142 /* gchar * path_string;*/
1144 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1145 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1147 /*if no model (so no rows at all), then virtually we are the first*/
1148 if (!priv->header_model)
1151 path = gtk_tree_row_reference_get_path (priv->row_reference);
1155 /* path_string = gtk_tree_path_to_string (path);
1156 is_first_selected = strcmp (path_string, "0");
1158 g_free (path_string);
1159 gtk_tree_path_free (path);
1161 return is_first_selected;*/
1163 is_first_selected = TRUE;
1164 while (is_first_selected) {
1166 if(!gtk_tree_path_prev (path))
1168 /* Here the 'if' is needless for logic, but let make sure
1169 * iter is valid for gtk_tree_model_get. */
1170 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1172 gtk_tree_model_get (priv->header_model, &tmp_iter,
1173 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1175 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1176 is_first_selected = FALSE;
1178 gtk_tree_path_free (path);
1179 return is_first_selected;
1183 * Reads the message whose summary item is @header. It takes care of
1184 * several things, among others:
1186 * If the message was not previously downloaded then ask the user
1187 * before downloading. If there is no connection launch the connection
1188 * dialog. Update toolbar dimming rules.
1190 * Returns: TRUE if the mail operation was started, otherwise if the
1191 * user do not want to download the message, or if the user do not
1192 * want to connect, then the operation is not issued
1195 message_reader (ModestMsgViewWindow *window,
1196 ModestMsgViewWindowPrivate *priv,
1200 ModestMailOperation *mail_op = NULL;
1201 ModestMailOperationTypeOperation op_type;
1202 gboolean already_showing = FALSE;
1203 ModestWindow *msg_window = NULL;
1204 ModestWindowMgr *mgr;
1206 g_return_val_if_fail (path != NULL, FALSE);
1208 mgr = modest_runtime_get_window_mgr ();
1209 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1210 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1213 gtk_window_present (GTK_WINDOW (msg_window));
1214 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1218 /* Msg download completed */
1219 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1220 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1223 GtkResponseType response;
1225 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1227 /* Ask the user if he wants to download the message */
1228 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1229 _("mcen_nc_get_msg"));
1230 if (response == GTK_RESPONSE_CANCEL)
1233 /* Offer the connection dialog if necessary */
1234 /* FIXME: should this stuff go directly to the mail
1235 operation instead of spread it all over the
1237 folder = tny_header_get_folder (header);
1239 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
1240 g_object_unref (folder);
1243 g_object_unref (folder);
1247 /* New mail operation */
1248 mail_op = modest_mail_operation_new_with_error_handling (op_type,
1250 modest_ui_actions_get_msgs_full_error_handler,
1253 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1254 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, path);
1255 g_object_unref (mail_op);
1257 /* Update toolbar dimming rules */
1258 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1264 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1266 ModestMsgViewWindowPrivate *priv;
1267 GtkTreePath *path= NULL;
1268 GtkTreeIter tmp_iter;
1270 gboolean retval = TRUE;
1272 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1273 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1275 /* Update the next row reference if it's not valid. This could
1276 happen if for example the header which it was pointing to,
1277 was deleted. The best place to do it is in the row-deleted
1278 handler but the tinymail model do not work like the glib
1279 tree models and reports the deletion when the row is still
1281 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1282 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1283 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1284 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1287 if (priv->next_row_reference)
1288 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1292 gtk_tree_model_get_iter (priv->header_model,
1296 gtk_tree_model_get (priv->header_model, &tmp_iter,
1297 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1300 /* Read the message & show it */
1301 if (!message_reader (window, priv, header, path)) {
1303 gtk_tree_path_free (path);
1307 g_object_unref (header);
1313 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1315 ModestMsgViewWindowPrivate *priv = NULL;
1316 TnyHeader *header = NULL;
1320 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1321 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1323 /* Check that the model is not empty */
1324 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1327 /* Get the header */
1328 gtk_tree_model_get (priv->header_model,
1330 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1332 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1333 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1334 g_object_unref (header);
1335 return modest_msg_view_window_select_next_message (self);
1338 path = gtk_tree_model_get_path (priv->header_model, &iter);
1340 /* Read the message & show it */
1341 message_reader (self, priv, header, path);
1344 g_object_unref (header);
1350 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1352 ModestMsgViewWindowPrivate *priv = NULL;
1355 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1356 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1358 /* Return inmediatly if there is no header model */
1359 if (!priv->header_model)
1362 path = gtk_tree_row_reference_get_path (priv->row_reference);
1363 while (gtk_tree_path_prev (path)) {
1367 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1368 gtk_tree_model_get (priv->header_model, &iter,
1369 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1373 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1374 g_object_unref (header);
1378 /* Read the message & show it */
1379 if (!message_reader (window, priv, header, path)) {
1380 g_object_unref (header);
1384 g_object_unref (header);
1389 gtk_tree_path_free (path);
1394 view_msg_cb (ModestMailOperation *mail_op,
1399 ModestMsgViewWindow *self = NULL;
1400 ModestMsgViewWindowPrivate *priv = NULL;
1403 /* If there was any error */
1404 path = (GtkTreePath *) user_data;
1405 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1406 gtk_tree_path_free (path);
1410 /* Get the window */
1411 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1412 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1413 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1415 /* Update the row reference */
1416 gtk_tree_row_reference_free (priv->row_reference);
1417 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1418 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1419 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1420 gtk_tree_path_free (path);
1422 /* Mark header as read */
1423 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1424 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
1426 /* Set new message */
1427 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
1428 modest_msg_view_window_update_priority (self);
1429 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1430 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1432 /* Set the new message uid of the window */
1433 if (priv->msg_uid) {
1434 g_free (priv->msg_uid);
1435 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1438 /* Notify the observers */
1439 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1440 0, priv->header_model, priv->row_reference);
1442 /* Free new references */
1443 g_object_unref (self);
1447 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1449 ModestMsgViewWindowPrivate *priv;
1451 TnyFolderType folder_type;
1453 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1455 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1457 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
1461 folder = tny_msg_get_folder (msg);
1464 folder_type = tny_folder_get_folder_type (folder);
1466 if (folder_type == TNY_FOLDER_TYPE_NORMAL || folder_type == TNY_FOLDER_TYPE_UNKNOWN) {
1467 const gchar *fname = tny_folder_get_name (folder);
1468 folder_type = modest_tny_folder_guess_folder_type_from_name (fname);
1471 g_object_unref (folder);
1473 g_object_unref (msg);
1481 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1483 ModestMsgViewWindowPrivate *priv;
1484 TnyHeaderFlags flags = 0;
1486 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1488 if (priv->header_model) {
1491 GtkTreePath *path = NULL;
1493 path = gtk_tree_row_reference_get_path (priv->row_reference);
1494 g_return_if_fail (path != NULL);
1495 gtk_tree_model_get_iter (priv->header_model,
1497 gtk_tree_row_reference_get_path (priv->row_reference));
1499 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1501 flags = tny_header_get_flags (header);
1502 gtk_tree_path_free (path);
1505 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1510 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1512 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1513 ModestWindowPrivate *parent_priv;
1514 ModestWindowMgr *mgr;
1515 gboolean is_fullscreen;
1516 GtkAction *fs_toggle_action;
1519 mgr = modest_runtime_get_window_mgr ();
1520 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1522 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1524 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1525 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1526 if (is_fullscreen != active) {
1527 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1536 modest_msg_view_window_toggle_fullscreen (ModestMsgViewWindow *window)
1538 ModestWindowPrivate *parent_priv;
1539 GtkAction *fs_toggle_action;
1540 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1542 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1543 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action),
1544 !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)));
1548 set_homogeneous (GtkWidget *widget,
1551 if (GTK_IS_TOOL_ITEM (widget)) {
1552 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1553 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1558 modest_msg_view_window_show_toolbar (ModestWindow *self,
1559 gboolean show_toolbar)
1561 ModestMsgViewWindowPrivate *priv = NULL;
1562 ModestWindowPrivate *parent_priv;
1563 GtkWidget *reply_button = NULL, *menu = NULL;
1564 GtkWidget *placeholder = NULL;
1567 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1568 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1570 /* Set optimized view status */
1571 priv->optimized_view = !show_toolbar;
1573 if (!parent_priv->toolbar) {
1574 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1577 /* Set homogeneous toolbar */
1578 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1579 set_homogeneous, NULL);
1581 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1582 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1583 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1584 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1585 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1586 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1587 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1588 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1590 /* Add ProgressBar (Transfer toolbar) */
1591 priv->progress_bar = modest_progress_bar_widget_new ();
1592 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1593 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1594 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1595 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1596 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1598 /* Connect cancel 'clicked' signal to abort progress mode */
1599 g_signal_connect(priv->cancel_toolitem, "clicked",
1600 G_CALLBACK(cancel_progressbar),
1603 /* Add it to the observers list */
1604 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1607 hildon_window_add_toolbar (HILDON_WINDOW (self),
1608 GTK_TOOLBAR (parent_priv->toolbar));
1611 /* Set reply button tap and hold menu */
1612 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1613 "/ToolBar/ToolbarMessageReply");
1614 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1615 "/ToolbarReplyCSM");
1616 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1620 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1621 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1622 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1624 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1625 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1628 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1629 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1634 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
1636 ModestMsgViewWindow *window)
1638 ModestWindowPrivate *parent_priv;
1639 /* GtkAction *action; */
1640 gboolean is_address;
1644 if (!GTK_WIDGET_VISIBLE (window))
1647 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1648 selection = gtk_clipboard_wait_for_text (clipboard);
1650 is_address = ((selection != NULL) && (modest_text_utils_validate_recipient (selection, NULL)));
1652 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsAddToContactsMenu"); */
1653 /* gtk_action_set_sensitive (action, is_address); */
1655 focused = gtk_window_get_focus (GTK_WINDOW (window));
1657 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/EditCopyMenu"); */
1658 /* gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused))); */
1660 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/EditCutMenu"); */
1661 /* gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused))); */
1664 /* modest_msg_view_window_update_dimmed (window); */
1669 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
1671 ModestMsgViewWindowPrivate *priv;
1673 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1674 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1676 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1680 cancel_progressbar (GtkToolButton *toolbutton,
1681 ModestMsgViewWindow *self)
1684 ModestMsgViewWindowPrivate *priv;
1686 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1688 /* Get operation observers and cancel its current operation */
1689 tmp = priv->progress_widgets;
1691 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1692 tmp=g_slist_next(tmp);
1696 observers_empty (ModestMsgViewWindow *self)
1699 ModestMsgViewWindowPrivate *priv;
1700 gboolean is_empty = TRUE;
1701 guint pending_ops = 0;
1703 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1704 tmp = priv->progress_widgets;
1706 /* Check all observers */
1707 while (tmp && is_empty) {
1708 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1709 is_empty = pending_ops == 0;
1711 tmp = g_slist_next(tmp);
1718 on_account_removed (TnyAccountStore *account_store,
1719 TnyAccount *account,
1722 /* Do nothing if it's a transport account, because we only
1723 show the messages of a store account */
1724 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
1725 const gchar *parent_acc = NULL;
1726 const gchar *our_acc = NULL;
1728 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
1729 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1731 /* Close this window if I'm showing a message of the removed account */
1732 if (strcmp (parent_acc, our_acc) == 0)
1733 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
1738 on_queue_changed (ModestMailOperationQueue *queue,
1739 ModestMailOperation *mail_op,
1740 ModestMailOperationQueueNotification type,
1741 ModestMsgViewWindow *self)
1744 ModestMsgViewWindowPrivate *priv;
1745 ModestMailOperationTypeOperation op_type;
1746 ModestToolBarModes mode;
1748 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1749 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1751 /* If this operations was created by another window, do nothing */
1752 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
1755 /* Get toolbar mode from operation id*/
1756 op_type = modest_mail_operation_get_type_operation (mail_op);
1758 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
1759 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1760 case MODEST_MAIL_OPERATION_TYPE_OPEN:
1761 mode = TOOLBAR_MODE_TRANSFER;
1764 mode = TOOLBAR_MODE_NORMAL;
1768 /* Add operation observers and change toolbar if neccessary*/
1769 tmp = priv->progress_widgets;
1771 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1772 if (mode == TOOLBAR_MODE_TRANSFER) {
1773 /* Enable transfer toolbar mode */
1774 set_toolbar_transfer_mode(self);
1776 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1778 tmp = g_slist_next (tmp);
1783 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1784 if (mode == TOOLBAR_MODE_TRANSFER) {
1786 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1788 tmp = g_slist_next (tmp);
1792 /* If no more operations are being observed, NORMAL mode is enabled again */
1793 if (observers_empty (self)) {
1794 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1802 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
1804 ModestMsgViewWindowPrivate *priv;
1805 GList *selected_attachments = NULL;
1807 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
1808 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
1810 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
1812 return selected_attachments;
1816 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
1818 ModestMsgViewWindowPrivate *priv;
1819 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1820 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
1822 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1824 if (mime_part == NULL) {
1825 gboolean error = FALSE;
1826 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
1827 if (selected_attachments == NULL) {
1829 } else if (g_list_length (selected_attachments) > 1) {
1830 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
1833 mime_part = (TnyMimePart *) selected_attachments->data;
1834 g_object_ref (mime_part);
1836 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
1837 g_list_free (selected_attachments);
1842 g_object_ref (mime_part);
1845 if (tny_mime_part_is_purged (mime_part)) {
1846 g_object_unref (mime_part);
1850 if (!TNY_IS_MSG (mime_part)) {
1851 gchar *filepath = NULL;
1852 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
1853 gchar *extension = NULL;
1854 TnyFsStream *temp_stream = NULL;
1857 extension = g_strrstr (att_filename, ".");
1858 if (extension != NULL)
1862 temp_stream = modest_maemo_utils_create_temp_stream (extension, &filepath);
1865 const gchar *content_type;
1866 content_type = tny_mime_part_get_content_type (mime_part);
1867 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
1869 modest_platform_activate_file (filepath, content_type);
1870 g_object_unref (temp_stream);
1872 /* TODO: delete temporary file */
1875 /* message attachment */
1876 TnyHeader *header = NULL;
1877 ModestWindowMgr *mgr;
1878 ModestWindow *msg_win = NULL;
1881 header = tny_msg_get_header (TNY_MSG (mime_part));
1882 mgr = modest_runtime_get_window_mgr ();
1883 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
1886 if (msg_win) /* there is already a window for this uid; top it */
1887 gtk_window_present (GTK_WINDOW(msg_win));
1889 /* if it's found, but there is no msg_win, it's probably in the process of being created;
1890 * thus, we don't do anything */
1891 g_warning ("window for is already being created");
1893 /* it's not found, so create a new window for it */
1894 modest_window_mgr_register_header (mgr, header); /* register the uid before building the window */
1895 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
1897 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
1898 msg_win = modest_msg_view_window_new (TNY_MSG (mime_part), account, NULL);
1899 modest_window_set_zoom (MODEST_WINDOW (msg_win),
1900 modest_window_get_zoom (MODEST_WINDOW (window)));
1901 modest_window_mgr_register_window (mgr, msg_win);
1902 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
1903 gtk_widget_show_all (GTK_WIDGET (msg_win));
1906 g_object_unref (mime_part);
1922 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
1923 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
1924 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
1925 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
1928 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
1932 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
1933 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
1934 g_free (pair->filename);
1935 g_object_unref (pair->part);
1936 g_slice_free (SaveMimePartPair, pair);
1938 g_list_free (info->pairs);
1941 gtk_widget_destroy (info->banner);
1942 g_object_unref (info->banner);
1943 g_slice_free (SaveMimePartInfo, info);
1948 idle_save_mime_part_show_result (SaveMimePartInfo *info)
1950 if (info->pairs != NULL) {
1951 /* This is a GDK lock because we are an idle callback and
1952 * save_mime_parts_to_file_with_checks can contain Gtk+ code */
1954 gdk_threads_enter (); /* CHECKED */
1955 save_mime_parts_to_file_with_checks (info);
1956 gdk_threads_leave (); /* CHECKED */
1959 result = info->result;
1961 /* This is a GDK lock because we are an idle callback and
1962 * hildon_banner_show_information is or does Gtk+ code */
1964 gdk_threads_enter (); /* CHECKED */
1965 save_mime_part_info_free (info, TRUE);
1967 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
1969 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
1971 gdk_threads_leave (); /* CHECKED */
1978 save_mime_part_to_file (SaveMimePartInfo *info)
1980 GnomeVFSResult result;
1981 GnomeVFSHandle *handle;
1983 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
1985 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0777);
1986 if (result == GNOME_VFS_OK) {
1987 stream = tny_vfs_stream_new (handle);
1988 tny_mime_part_decode_to_stream (pair->part, stream);
1989 g_object_unref (G_OBJECT (stream));
1990 g_object_unref (pair->part);
1991 g_slice_free (SaveMimePartPair, pair);
1992 info->pairs = g_list_delete_link (info->pairs, info->pairs);
1993 info->result = TRUE;
1995 save_mime_part_info_free (info, FALSE);
1996 info->result = FALSE;
1999 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2004 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2006 SaveMimePartPair *pair;
2007 gboolean is_ok = TRUE;
2009 pair = info->pairs->data;
2010 if (modest_maemo_utils_file_exists (pair->filename)) {
2011 GtkWidget *confirm_overwrite_dialog;
2012 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL,
2013 _("emev_nc_replace_files"));
2014 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2017 gtk_widget_destroy (confirm_overwrite_dialog);
2021 save_mime_part_info_free (info, TRUE);
2023 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2030 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2032 gboolean clean_list = FALSE;
2033 ModestMsgViewWindowPrivate *priv;
2034 GList *files_to_save = NULL;
2035 GtkWidget *save_dialog = NULL;
2036 gchar *folder = NULL;
2037 gboolean canceled = FALSE;
2038 const gchar *filename = NULL;
2039 gchar *save_multiple_str = NULL;
2041 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2042 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2044 if (mime_parts == NULL) {
2045 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2046 if (mime_parts == NULL)
2051 /* prepare dialog */
2052 if (mime_parts->next == NULL) {
2053 /* only one attachment selected */
2054 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2055 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2056 filename = tny_mime_part_get_filename (mime_part);
2058 g_warning ("Tried to save a non-file attachment");
2062 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2063 g_list_length (mime_parts));
2066 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2067 GTK_FILE_CHOOSER_ACTION_SAVE);
2070 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2071 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2075 if (filename != NULL)
2076 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2079 /* if multiple, set multiple string */
2080 if (save_multiple_str) {
2081 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2085 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2086 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2088 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2089 hildon_banner_show_information
2090 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2094 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2095 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2097 if (tny_mime_part_is_attachment (mime_part)) {
2098 SaveMimePartPair *pair;
2100 if ((mime_parts->next != NULL) &&
2101 (tny_mime_part_get_filename (mime_part) == NULL))
2104 pair = g_slice_new0 (SaveMimePartPair);
2105 if (mime_parts->next == NULL) {
2106 pair->filename = g_strdup (chooser_uri);
2109 g_build_filename (chooser_uri,
2110 tny_mime_part_get_filename (mime_part), NULL);
2112 pair->part = g_object_ref (mime_part);
2113 files_to_save = g_list_prepend (files_to_save, pair);
2117 g_free (chooser_uri);
2120 gtk_widget_destroy (save_dialog);
2123 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2124 g_list_free (mime_parts);
2127 if (files_to_save != NULL) {
2128 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2129 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2130 _CS("sfil_ib_saving"));
2131 info->pairs = files_to_save;
2132 info->banner = banner;
2133 info->result = TRUE;
2134 g_object_ref (banner);
2135 save_mime_parts_to_file_with_checks (info);
2140 show_remove_attachment_information (gpointer userdata)
2142 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2143 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2145 if (priv->remove_attachment_banner != NULL) {
2146 gtk_widget_destroy (priv->remove_attachment_banner);
2147 g_object_unref (priv->remove_attachment_banner);
2150 priv->remove_attachment_banner = g_object_ref (
2151 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2157 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2159 ModestMsgViewWindowPrivate *priv;
2160 GList *mime_parts = NULL, *node;
2161 gchar *confirmation_message;
2165 /* TnyFolder *folder; */
2167 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2168 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2171 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2173 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2175 /* Remove already purged messages from mime parts list */
2177 while (node != NULL) {
2178 TnyMimePart *part = TNY_MIME_PART (node->data);
2179 if (tny_mime_part_is_purged (part)) {
2180 GList *deleted_node = node;
2181 node = g_list_next (node);
2182 g_object_unref (part);
2183 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2185 node = g_list_next (node);
2189 if (mime_parts == NULL)
2192 n_attachments = g_list_length (mime_parts);
2193 if (n_attachments == 1) {
2194 const gchar *filename;
2196 if (TNY_IS_MSG (mime_parts->data)) {
2198 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2199 filename = tny_header_get_subject (header);
2200 g_object_unref (header);
2201 if (filename == NULL)
2202 filename = _("mail_va_no_subject");
2204 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2206 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2208 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2209 "mcen_nc_purge_files_text",
2210 n_attachments), n_attachments);
2212 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2213 confirmation_message);
2214 g_free (confirmation_message);
2216 if (response != GTK_RESPONSE_OK)
2219 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2220 /* folder = tny_msg_get_folder (msg); */
2221 /* tny_msg_uncache_attachments (msg); */
2222 /* tny_folder_refresh (folder, NULL); */
2223 /* g_object_unref (folder); */
2225 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2226 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2227 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2230 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2231 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), NULL);
2232 tny_msg_rewrite_cache (msg);
2233 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
2235 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2236 g_list_free (mime_parts);
2238 if (priv->purge_timeout > 0) {
2239 g_source_remove (priv->purge_timeout);
2240 priv->purge_timeout = 0;
2243 if (priv->remove_attachment_banner) {
2244 gtk_widget_destroy (priv->remove_attachment_banner);
2245 g_object_unref (priv->remove_attachment_banner);
2246 priv->remove_attachment_banner = NULL;
2254 update_window_title (ModestMsgViewWindow *window)
2256 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2258 TnyHeader *header = NULL;
2259 const gchar *subject = NULL;
2261 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2263 header = tny_msg_get_header (msg);
2264 subject = tny_header_get_subject (header);
2265 g_object_unref (msg);
2268 if ((subject == NULL)||(subject[0] == '\0'))
2269 subject = _("mail_va_no_subject");
2271 gtk_window_set_title (GTK_WINDOW (window), subject);