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);
93 static void cancel_progressbar (GtkToolButton *toolbutton,
94 ModestMsgViewWindow *self);
96 static void on_queue_changed (ModestMailOperationQueue *queue,
97 ModestMailOperation *mail_op,
98 ModestMailOperationQueueNotification type,
99 ModestMsgViewWindow *self);
101 static void on_account_removed (TnyAccountStore *account_store,
105 static void view_msg_cb (ModestMailOperation *mail_op,
110 static void set_toolbar_mode (ModestMsgViewWindow *self,
111 ModestToolBarModes mode);
113 static void update_window_title (ModestMsgViewWindow *window);
115 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
118 /* list my signals */
124 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
125 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
126 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
129 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
130 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
131 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
132 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
133 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
134 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
135 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
138 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
139 struct _ModestMsgViewWindowPrivate {
142 GtkWidget *main_scroll;
143 GtkWidget *find_toolbar;
146 /* Progress observers */
147 GtkWidget *progress_bar;
148 GSList *progress_widgets;
151 GtkWidget *progress_toolitem;
152 GtkWidget *cancel_toolitem;
153 GtkWidget *prev_toolitem;
154 GtkWidget *next_toolitem;
155 ModestToolBarModes current_toolbar_mode;
157 /* Optimized view enabled */
158 gboolean optimized_view;
160 /* A reference to the @model of the header view
161 * to allow selecting previous/next messages,
162 * if the message is currently selected in the header view.
164 GtkTreeModel *header_model;
165 GtkTreeRowReference *row_reference;
166 GtkTreeRowReference *next_row_reference;
168 guint clipboard_change_handler;
169 guint queue_change_handler;
170 guint account_removed_handler;
173 GtkWidget *remove_attachment_banner;
175 guint progress_bar_timeout;
180 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
181 MODEST_TYPE_MSG_VIEW_WINDOW, \
182 ModestMsgViewWindowPrivate))
184 static GtkWindowClass *parent_class = NULL;
186 /* uncomment the following if you have defined any signals */
187 static guint signals[LAST_SIGNAL] = {0};
190 modest_msg_view_window_get_type (void)
192 static GType my_type = 0;
194 static const GTypeInfo my_info = {
195 sizeof(ModestMsgViewWindowClass),
196 NULL, /* base init */
197 NULL, /* base finalize */
198 (GClassInitFunc) modest_msg_view_window_class_init,
199 NULL, /* class finalize */
200 NULL, /* class data */
201 sizeof(ModestMsgViewWindow),
203 (GInstanceInitFunc) modest_msg_view_window_init,
206 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
207 "ModestMsgViewWindow",
214 save_state (ModestWindow *self)
216 modest_widget_memory_save (modest_runtime_get_conf (),
218 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
223 restore_settings (ModestMsgViewWindow *self)
225 modest_widget_memory_restore (modest_runtime_get_conf (),
227 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
231 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
233 GObjectClass *gobject_class;
234 ModestWindowClass *modest_window_class;
235 gobject_class = (GObjectClass*) klass;
236 modest_window_class = (ModestWindowClass *) klass;
238 parent_class = g_type_class_peek_parent (klass);
239 gobject_class->finalize = modest_msg_view_window_finalize;
241 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
242 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
243 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
244 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
245 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
246 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
248 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
250 modest_window_class->save_state_func = save_state;
252 signals[MSG_CHANGED_SIGNAL] =
253 g_signal_new ("msg-changed",
254 G_TYPE_FROM_CLASS (gobject_class),
256 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
258 modest_marshal_VOID__POINTER_POINTER,
259 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
263 modest_msg_view_window_init (ModestMsgViewWindow *obj)
265 ModestMsgViewWindowPrivate *priv;
266 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
268 priv->msg_view = NULL;
269 priv->header_model = NULL;
270 priv->clipboard_change_handler = 0;
271 priv->queue_change_handler = 0;
272 priv->account_removed_handler = 0;
273 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
275 priv->optimized_view = FALSE;
276 priv->progress_bar_timeout = 0;
277 priv->purge_timeout = 0;
278 priv->remove_attachment_banner = NULL;
279 priv->msg_uid = NULL;
284 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
286 ModestMsgViewWindowPrivate *priv = NULL;
288 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
290 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
292 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
294 if (priv->progress_bar_timeout > 0) {
295 g_source_remove (priv->progress_bar_timeout);
296 priv->progress_bar_timeout = 0;
303 set_toolbar_mode (ModestMsgViewWindow *self,
304 ModestToolBarModes mode)
306 ModestWindowPrivate *parent_priv;
307 ModestMsgViewWindowPrivate *priv;
308 /* GtkWidget *widget = NULL; */
310 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
312 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
313 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
315 /* Sets current toolbar mode */
316 priv->current_toolbar_mode = mode;
318 /* Update toolbar dimming state */
319 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
322 case TOOLBAR_MODE_NORMAL:
323 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
324 /* gtk_action_set_sensitive (widget, TRUE); */
325 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
326 /* gtk_action_set_sensitive (widget, TRUE); */
327 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
328 /* gtk_action_set_sensitive (widget, TRUE); */
329 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
330 /* gtk_action_set_sensitive (widget, TRUE); */
332 if (priv->prev_toolitem)
333 gtk_widget_show (priv->prev_toolitem);
335 if (priv->next_toolitem)
336 gtk_widget_show (priv->next_toolitem);
338 if (priv->progress_toolitem)
339 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
340 if (priv->progress_bar)
341 gtk_widget_hide (priv->progress_bar);
343 if (priv->cancel_toolitem)
344 gtk_widget_hide (priv->cancel_toolitem);
346 /* Hide toolbar if optimized view is enabled */
347 if (priv->optimized_view) {
348 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
349 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
353 case TOOLBAR_MODE_TRANSFER:
354 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
355 /* gtk_action_set_sensitive (widget, FALSE); */
356 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
357 /* gtk_action_set_sensitive (widget, FALSE); */
358 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
359 /* gtk_action_set_sensitive (widget, FALSE); */
360 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
361 /* gtk_action_set_sensitive (widget, FALSE); */
363 if (priv->prev_toolitem)
364 gtk_widget_hide (priv->prev_toolitem);
366 if (priv->next_toolitem)
367 gtk_widget_hide (priv->next_toolitem);
369 if (priv->progress_toolitem)
370 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
371 if (priv->progress_bar)
372 gtk_widget_show (priv->progress_bar);
374 if (priv->cancel_toolitem)
375 gtk_widget_show (priv->cancel_toolitem);
377 /* Show toolbar if it's hiden (optimized view ) */
378 if (priv->optimized_view) {
379 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
380 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
385 g_return_if_reached ();
392 menubar_to_menu (GtkUIManager *ui_manager)
394 GtkWidget *main_menu;
398 /* Create new main menu */
399 main_menu = gtk_menu_new();
401 /* Get the menubar from the UI manager */
402 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
404 iter = gtk_container_get_children (GTK_CONTAINER (menubar));
408 menu = GTK_WIDGET (iter->data);
409 gtk_widget_reparent(menu, main_menu);
411 iter = g_list_next (iter);
417 init_window (ModestMsgViewWindow *obj, TnyMsg *msg)
419 GtkWidget *main_vbox;
420 ModestMsgViewWindowPrivate *priv;
421 ModestWindowPrivate *parent_priv;
423 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
424 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
426 priv->msg_view = modest_msg_view_new (msg);
427 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
428 main_vbox = gtk_vbox_new (FALSE, 6);
431 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
432 gtk_widget_show_all (GTK_WIDGET(parent_priv->menubar));
433 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
435 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
436 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
437 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
438 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
440 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
441 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
442 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
444 priv->find_toolbar = hildon_find_toolbar_new (NULL);
445 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
446 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
447 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
448 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
450 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);
451 gtk_widget_show_all (GTK_WIDGET(main_vbox));
455 modest_msg_view_window_disconnect_signals (ModestWindow *self)
457 ModestMsgViewWindowPrivate *priv;
459 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
461 if (g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
462 priv->clipboard_change_handler))
463 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
464 priv->clipboard_change_handler);
466 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
467 priv->queue_change_handler))
468 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
469 priv->queue_change_handler);
471 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
472 priv->account_removed_handler))
473 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
474 priv->account_removed_handler);
478 modest_msg_view_window_finalize (GObject *obj)
480 ModestMsgViewWindowPrivate *priv;
482 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
484 /* Sanity check: shouldn't be needed, the window mgr should
485 call this function before */
486 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
488 if (priv->header_model != NULL) {
489 g_object_unref (priv->header_model);
490 priv->header_model = NULL;
493 if (priv->progress_bar_timeout > 0) {
494 g_source_remove (priv->progress_bar_timeout);
495 priv->progress_bar_timeout = 0;
498 if (priv->remove_attachment_banner) {
499 gtk_widget_destroy (priv->remove_attachment_banner);
500 g_object_unref (priv->remove_attachment_banner);
501 priv->remove_attachment_banner = NULL;
504 if (priv->purge_timeout > 0) {
505 g_source_remove (priv->purge_timeout);
506 priv->purge_timeout = 0;
509 if (priv->row_reference) {
510 gtk_tree_row_reference_free (priv->row_reference);
511 priv->row_reference = NULL;
514 if (priv->next_row_reference) {
515 gtk_tree_row_reference_free (priv->next_row_reference);
516 priv->next_row_reference = NULL;
520 g_free (priv->msg_uid);
521 priv->msg_uid = NULL;
524 G_OBJECT_CLASS(parent_class)->finalize (obj);
528 select_next_valid_row (GtkTreeModel *model,
529 GtkTreeRowReference **row_reference,
532 GtkTreeIter tmp_iter;
533 GtkTreePath *path, *next;
534 gboolean retval = FALSE;
536 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
538 path = gtk_tree_row_reference_get_path (*row_reference);
539 gtk_tree_model_get_iter (model, &tmp_iter, path);
540 gtk_tree_row_reference_free (*row_reference);
541 *row_reference = NULL;
543 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
544 next = gtk_tree_model_get_path (model, &tmp_iter);
545 *row_reference = gtk_tree_row_reference_new (model, next);
547 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
548 next = gtk_tree_model_get_path (model, &tmp_iter);
550 /* Ensure that we are not selecting the same */
551 if (gtk_tree_path_compare (path, next) != 0) {
552 *row_reference = gtk_tree_row_reference_new (model, next);
558 gtk_tree_path_free (path);
564 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
565 const gchar *modest_account_name,
566 const gchar *msg_uid,
568 GtkTreeRowReference *row_reference)
570 ModestMsgViewWindow *window = NULL;
571 ModestMsgViewWindowPrivate *priv = NULL;
573 window = MODEST_MSG_VIEW_WINDOW(modest_msg_view_window_new (msg, modest_account_name, msg_uid));
574 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
576 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
578 g_object_ref (model);
579 priv->header_model = model;
580 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
581 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
582 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
584 modest_msg_view_window_update_priority (window);
586 /* Check toolbar dimming rules */
587 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
589 return MODEST_WINDOW(window);
594 modest_msg_view_window_new (TnyMsg *msg,
595 const gchar *modest_account_name,
596 const gchar *msg_uid)
598 ModestMsgViewWindow *self = NULL;
600 ModestMsgViewWindowPrivate *priv = NULL;
601 ModestWindowPrivate *parent_priv = NULL;
602 ModestDimmingRulesGroup *menu_rules_group = NULL;
603 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
604 GtkActionGroup *action_group = NULL;
605 GError *error = NULL;
606 GdkPixbuf *window_icon;
608 g_return_val_if_fail (msg, NULL);
610 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
611 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
612 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
613 self = MODEST_MSG_VIEW_WINDOW (obj);
615 priv->msg_uid = g_strdup (msg_uid);
617 parent_priv->ui_manager = gtk_ui_manager_new();
618 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
620 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
621 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
623 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
624 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
626 /* Add common actions */
627 gtk_action_group_add_actions (action_group,
628 modest_action_entries,
629 G_N_ELEMENTS (modest_action_entries),
631 gtk_action_group_add_toggle_actions (action_group,
632 modest_toggle_action_entries,
633 G_N_ELEMENTS (modest_toggle_action_entries),
635 gtk_action_group_add_toggle_actions (action_group,
636 msg_view_toggle_action_entries,
637 G_N_ELEMENTS (msg_view_toggle_action_entries),
639 gtk_action_group_add_radio_actions (action_group,
640 msg_view_zoom_action_entries,
641 G_N_ELEMENTS (msg_view_zoom_action_entries),
643 G_CALLBACK (modest_ui_actions_on_change_zoom),
646 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
647 g_object_unref (action_group);
649 /* Load the UI definition */
650 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
653 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
654 g_error_free (error);
659 /* Add common dimming rules */
660 modest_dimming_rules_group_add_rules (menu_rules_group,
661 modest_msg_view_menu_dimming_entries,
662 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
664 modest_dimming_rules_group_add_rules (toolbar_rules_group,
665 modest_msg_view_toolbar_dimming_entries,
666 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
669 /* Insert dimming rules group for this window */
670 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
671 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
672 g_object_unref (menu_rules_group);
673 g_object_unref (toolbar_rules_group);
675 /* Add accelerators */
676 gtk_window_add_accel_group (GTK_WINDOW (obj),
677 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
680 init_window (MODEST_MSG_VIEW_WINDOW(obj), msg);
681 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
683 /* Set window icon */
684 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
686 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
687 g_object_unref (window_icon);
690 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
692 g_signal_connect (G_OBJECT(priv->msg_view), "link_clicked",
693 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
694 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
695 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
696 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
697 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
698 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
699 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
700 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
701 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
703 g_signal_connect (G_OBJECT (obj), "key-release-event",
704 G_CALLBACK (modest_msg_view_window_key_release_event),
707 g_signal_connect (G_OBJECT (obj), "window-state-event",
708 G_CALLBACK (modest_msg_view_window_window_state_event),
711 /* Mail Operation Queue */
712 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
714 G_CALLBACK (on_queue_changed),
717 /* Account manager */
718 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
720 G_CALLBACK(on_account_removed),
723 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
725 priv->last_search = NULL;
727 /* Init the clipboard actions dim status */
728 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
730 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
732 /* Check toolbar dimming rules */
733 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
735 return MODEST_WINDOW(obj);
740 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
742 ModestMsgViewWindowPrivate *priv= NULL;
744 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
745 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
747 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
751 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
753 ModestMsgViewWindowPrivate *priv= NULL;
755 TnyHeader *header = NULL;
756 GtkTreePath *path = NULL;
759 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
760 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
762 /* If the message ws not obtained from a treemodel,
763 * for instance if it was opened directly by the search UI:
765 if (priv->header_model == NULL) {
766 msg = modest_msg_view_window_get_message (self);
767 header = tny_msg_get_header (msg);
768 g_object_unref (msg);
772 /* Get iter of the currently selected message in the header view: */
773 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
774 * instead of sometimes retrieving it from the header view?
775 * Then we wouldn't be dependent on the message actually still being selected
776 * in the header view. murrayc. */
777 path = gtk_tree_row_reference_get_path (priv->row_reference);
778 g_return_val_if_fail (path != NULL, NULL);
779 gtk_tree_model_get_iter (priv->header_model,
783 /* Get current message header */
784 gtk_tree_model_get (priv->header_model, &iter,
785 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
788 gtk_tree_path_free (path);
793 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
795 ModestMsgView *msg_view;
796 ModestMsgViewWindowPrivate *priv;
798 g_return_val_if_fail (self, NULL);
800 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
802 msg_view = MODEST_MSG_VIEW (priv->msg_view);
804 return modest_msg_view_get_message (msg_view);
808 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
810 ModestMsgViewWindowPrivate *priv;
812 g_return_val_if_fail (self, NULL);
814 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
816 return (const gchar*) priv->msg_uid;
820 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
823 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
824 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
825 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
829 is_active = gtk_toggle_action_get_active (toggle);
832 gtk_widget_show (priv->find_toolbar);
833 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
835 gtk_widget_hide (priv->find_toolbar);
838 /* update the toggle buttons status */
839 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
840 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
841 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
842 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
847 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
848 ModestMsgViewWindow *obj)
850 GtkToggleAction *toggle;
851 ModestWindowPrivate *parent_priv;
852 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
854 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
855 gtk_toggle_action_set_active (toggle, FALSE);
859 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
860 ModestMsgViewWindow *obj)
862 gchar *current_search;
863 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
865 if (modest_msg_view_get_message_is_empty (MODEST_MSG_VIEW (priv->msg_view))) {
866 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
870 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
872 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
873 g_free (current_search);
874 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
878 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
880 g_free (priv->last_search);
881 priv->last_search = g_strdup (current_search);
882 result = modest_msg_view_search (MODEST_MSG_VIEW (priv->msg_view),
885 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
886 g_free (priv->last_search);
887 priv->last_search = NULL;
890 if (!modest_msg_view_search_next (MODEST_MSG_VIEW (priv->msg_view))) {
891 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
892 g_free (priv->last_search);
893 priv->last_search = NULL;
897 g_free (current_search);
902 modest_msg_view_window_set_zoom (ModestWindow *window,
905 ModestMsgViewWindowPrivate *priv;
907 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
909 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
910 modest_msg_view_set_zoom (MODEST_MSG_VIEW (priv->msg_view), zoom);
914 modest_msg_view_window_get_zoom (ModestWindow *window)
916 ModestMsgViewWindowPrivate *priv;
918 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
920 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
921 return modest_msg_view_get_zoom (MODEST_MSG_VIEW (priv->msg_view));
925 modest_msg_view_window_zoom_plus (ModestWindow *window)
927 ModestWindowPrivate *parent_priv;
928 GtkRadioAction *zoom_radio_action;
929 GSList *group, *node;
931 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
932 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
933 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
935 group = gtk_radio_action_get_group (zoom_radio_action);
937 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
938 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
942 for (node = group; node != NULL; node = g_slist_next (node)) {
943 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
944 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
952 modest_msg_view_window_zoom_minus (ModestWindow *window)
954 ModestWindowPrivate *parent_priv;
955 GtkRadioAction *zoom_radio_action;
956 GSList *group, *node;
958 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
959 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
960 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
962 group = gtk_radio_action_get_group (zoom_radio_action);
964 for (node = group; node != NULL; node = g_slist_next (node)) {
965 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
966 if (node->next != NULL) {
967 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
970 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
980 modest_msg_view_window_key_release_event (GtkWidget *window,
984 if (event->type == GDK_KEY_RELEASE) {
985 switch (event->keyval) {
987 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
991 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1004 modest_msg_view_window_scroll_up (ModestWindow *window)
1006 ModestMsgViewWindowPrivate *priv;
1007 gboolean return_value;
1009 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1010 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1014 modest_msg_view_window_scroll_down (ModestWindow *window)
1016 ModestMsgViewWindowPrivate *priv;
1017 gboolean return_value;
1019 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1020 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1024 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1027 ModestMsgViewWindowPrivate *priv;
1028 GtkTreeIter tmp_iter;
1029 gboolean has_next = FALSE;
1031 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1032 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1034 if (priv->header_model) {
1035 path = gtk_tree_row_reference_get_path (priv->row_reference);
1036 if (path == NULL) return FALSE;
1039 gtk_tree_path_next (path);
1040 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1042 gtk_tree_model_get (priv->header_model, &tmp_iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1044 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) {
1049 gtk_tree_path_free (path);
1058 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1060 ModestMsgViewWindowPrivate *priv;
1062 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1063 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1065 return priv->header_model != NULL;
1069 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1072 ModestMsgViewWindowPrivate *priv;
1074 GtkTreeIter tmp_iter;
1076 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1077 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1079 if (priv->header_model) {
1080 gchar * path_string;
1081 path = gtk_tree_row_reference_get_path (priv->row_reference);
1085 path_string = gtk_tree_path_to_string (path);
1086 result = (strcmp (path_string, "0")==0);
1088 g_free (path_string);
1089 gtk_tree_path_free (path);
1096 gtk_tree_path_prev (path);
1098 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1100 gtk_tree_model_get (priv->header_model, &tmp_iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1102 if (!(tny_header_get_flags(header)&TNY_HEADER_FLAG_DELETED)) {
1107 path_string = gtk_tree_path_to_string (path);
1108 if (strcmp(path_string, "0")==0) {
1109 g_free (path_string);
1112 g_free (path_string);
1114 gtk_tree_path_free (path);
1123 * Reads the message whose summary item is @header. It takes care of
1124 * several things, among others:
1126 * If the message was not previously downloaded then ask the user
1127 * before downloading. If there is no connection launch the connection
1128 * dialog. Update toolbar dimming rules.
1130 * Returns: TRUE if the mail operation was started, otherwise if the
1131 * user do not want to download the message, or if the user do not
1132 * want to connect, then the operation is not issued
1135 message_reader (ModestMsgViewWindow *window,
1136 ModestMsgViewWindowPrivate *priv,
1140 ModestMailOperation *mail_op = NULL;
1141 ModestMailOperationTypeOperation op_type;
1142 gboolean already_showing = FALSE;
1143 ModestWindow *msg_window = NULL;
1144 ModestWindowMgr *mgr;
1146 g_return_val_if_fail (path != NULL, FALSE);
1148 mgr = modest_runtime_get_window_mgr ();
1149 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1150 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1153 gtk_window_present (GTK_WINDOW (msg_window));
1154 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1158 /* Msg download completed */
1159 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1160 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1163 GtkResponseType response;
1165 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1167 /* Ask the user if he wants to download the message */
1168 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1169 _("mcen_nc_get_msg"));
1170 if (response == GTK_RESPONSE_CANCEL)
1173 /* Offer the connection dialog if necessary */
1174 /* FIXME: should this stuff go directly to the mail
1175 operation instead of spread it all over the
1177 folder = tny_header_get_folder (header);
1179 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
1180 g_object_unref (folder);
1183 g_object_unref (folder);
1187 /* New mail operation */
1188 mail_op = modest_mail_operation_new_with_error_handling (op_type,
1190 modest_ui_actions_get_msgs_full_error_handler,
1193 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1194 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, path);
1195 g_object_unref (mail_op);
1197 /* Update toolbar dimming rules */
1198 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1204 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1206 ModestMsgViewWindowPrivate *priv;
1207 GtkTreePath *path= NULL;
1208 GtkTreeIter tmp_iter;
1210 gboolean retval = TRUE;
1212 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1213 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1215 /* Update the next row reference if it's not valid. This could
1216 happen if for example the header which it was pointing to,
1217 was deleted. The best place to do it is in the row-deleted
1218 handler but the tinymail model do not work like the glib
1219 tree models and reports the deletion when the row is still
1221 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1222 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1223 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1224 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1227 if (priv->next_row_reference)
1228 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1232 gtk_tree_model_get_iter (priv->header_model,
1236 gtk_tree_model_get (priv->header_model, &tmp_iter,
1237 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1240 /* Read the message & show it */
1241 if (!message_reader (window, priv, header, path)) {
1243 gtk_tree_path_free (path);
1247 g_object_unref (header);
1253 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1255 ModestMsgViewWindowPrivate *priv = NULL;
1256 TnyHeader *header = NULL;
1260 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1261 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1263 /* Check that the model is not empty */
1264 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1267 /* Get the header */
1268 gtk_tree_model_get (priv->header_model,
1270 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1272 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1273 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1274 g_object_unref (header);
1275 return modest_msg_view_window_select_next_message (self);
1278 path = gtk_tree_model_get_path (priv->header_model, &iter);
1280 /* Read the message & show it */
1281 message_reader (self, priv, header, path);
1284 g_object_unref (header);
1290 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1292 ModestMsgViewWindowPrivate *priv = NULL;
1295 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1296 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1298 /* Return inmediatly if there is no header model */
1299 if (!priv->header_model)
1302 path = gtk_tree_row_reference_get_path (priv->row_reference);
1303 while (gtk_tree_path_prev (path)) {
1307 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1308 gtk_tree_model_get (priv->header_model, &iter,
1309 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1313 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1314 g_object_unref (header);
1318 /* Read the message & show it */
1319 if (!message_reader (window, priv, header, path)) {
1320 g_object_unref (header);
1324 g_object_unref (header);
1329 gtk_tree_path_free (path);
1334 view_msg_cb (ModestMailOperation *mail_op,
1339 ModestMsgViewWindow *self = NULL;
1340 ModestMsgViewWindowPrivate *priv = NULL;
1343 /* If there was any error */
1344 path = (GtkTreePath *) user_data;
1345 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1346 gtk_tree_path_free (path);
1350 /* Get the window */
1351 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1352 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1353 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1355 /* Update the row reference */
1356 gtk_tree_row_reference_free (priv->row_reference);
1357 priv->row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1358 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1359 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1360 gtk_tree_path_free (path);
1362 /* Mark header as read */
1363 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1364 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
1366 /* Set new message */
1367 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
1368 modest_msg_view_window_update_priority (self);
1369 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1370 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1372 /* Set the new message uid of the window */
1373 if (priv->msg_uid) {
1374 g_free (priv->msg_uid);
1375 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1378 /* Notify the observers */
1379 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1380 0, priv->header_model, priv->row_reference);
1382 /* Free new references */
1383 g_object_unref (self);
1387 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1389 ModestMsgViewWindowPrivate *priv;
1391 TnyFolderType folder_type;
1393 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1395 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1397 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
1401 folder = tny_msg_get_folder (msg);
1404 folder_type = tny_folder_get_folder_type (folder);
1406 if (folder_type == TNY_FOLDER_TYPE_NORMAL || folder_type == TNY_FOLDER_TYPE_UNKNOWN) {
1407 const gchar *fname = tny_folder_get_name (folder);
1408 folder_type = modest_tny_folder_guess_folder_type_from_name (fname);
1411 g_object_unref (folder);
1413 g_object_unref (msg);
1421 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1423 ModestMsgViewWindowPrivate *priv;
1424 TnyHeaderFlags flags = 0;
1426 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1428 if (priv->header_model) {
1431 GtkTreePath *path = NULL;
1433 path = gtk_tree_row_reference_get_path (priv->row_reference);
1434 g_return_if_fail (path != NULL);
1435 gtk_tree_model_get_iter (priv->header_model,
1437 gtk_tree_row_reference_get_path (priv->row_reference));
1439 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1441 flags = tny_header_get_flags (header);
1442 gtk_tree_path_free (path);
1445 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1450 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1452 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1453 ModestWindowPrivate *parent_priv;
1454 ModestWindowMgr *mgr;
1455 gboolean is_fullscreen;
1456 GtkAction *fs_toggle_action;
1459 mgr = modest_runtime_get_window_mgr ();
1460 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1462 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1464 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1465 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1466 if (is_fullscreen != active) {
1467 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1476 modest_msg_view_window_toggle_fullscreen (ModestMsgViewWindow *window)
1478 ModestWindowPrivate *parent_priv;
1479 GtkAction *fs_toggle_action;
1480 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1482 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1483 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action),
1484 !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)));
1488 set_homogeneous (GtkWidget *widget,
1491 if (GTK_IS_TOOL_ITEM (widget)) {
1492 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1493 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1498 modest_msg_view_window_show_toolbar (ModestWindow *self,
1499 gboolean show_toolbar)
1501 ModestMsgViewWindowPrivate *priv = NULL;
1502 ModestWindowPrivate *parent_priv;
1503 GtkWidget *reply_button = NULL, *menu = NULL;
1504 GtkWidget *placeholder = NULL;
1507 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1508 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1510 /* Set optimized view status */
1511 priv->optimized_view = !show_toolbar;
1513 if (!parent_priv->toolbar) {
1514 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1517 /* Set homogeneous toolbar */
1518 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1519 set_homogeneous, NULL);
1521 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1522 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1523 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1524 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1525 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1526 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1527 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1528 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1530 /* Add ProgressBar (Transfer toolbar) */
1531 priv->progress_bar = modest_progress_bar_widget_new ();
1532 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1533 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1534 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1535 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1536 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1538 /* Connect cancel 'clicked' signal to abort progress mode */
1539 g_signal_connect(priv->cancel_toolitem, "clicked",
1540 G_CALLBACK(cancel_progressbar),
1543 /* Add it to the observers list */
1544 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1547 hildon_window_add_toolbar (HILDON_WINDOW (self),
1548 GTK_TOOLBAR (parent_priv->toolbar));
1551 /* Set reply button tap and hold menu */
1552 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1553 "/ToolBar/ToolbarMessageReply");
1554 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1555 "/ToolbarReplyCSM");
1556 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1560 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1561 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1562 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1564 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1565 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1568 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1569 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1574 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
1576 ModestMsgViewWindow *window)
1578 ModestWindowPrivate *parent_priv;
1579 /* GtkAction *action; */
1580 gboolean is_address;
1584 if (!GTK_WIDGET_VISIBLE (window))
1587 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1588 selection = gtk_clipboard_wait_for_text (clipboard);
1590 is_address = ((selection != NULL) && (modest_text_utils_validate_recipient (selection, NULL)));
1592 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsAddToContactsMenu"); */
1593 /* gtk_action_set_sensitive (action, is_address); */
1595 focused = gtk_window_get_focus (GTK_WINDOW (window));
1597 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/EditCopyMenu"); */
1598 /* gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused))); */
1600 /* action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/EditMenu/EditCutMenu"); */
1601 /* gtk_action_set_sensitive (action, (selection != NULL) && (!MODEST_IS_ATTACHMENTS_VIEW (focused))); */
1604 /* modest_msg_view_window_update_dimmed (window); */
1609 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
1611 ModestMsgViewWindowPrivate *priv;
1613 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1614 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1616 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1620 cancel_progressbar (GtkToolButton *toolbutton,
1621 ModestMsgViewWindow *self)
1624 ModestMsgViewWindowPrivate *priv;
1626 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1628 /* Get operation observers and cancel its current operation */
1629 tmp = priv->progress_widgets;
1631 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1632 tmp=g_slist_next(tmp);
1636 observers_empty (ModestMsgViewWindow *self)
1639 ModestMsgViewWindowPrivate *priv;
1640 gboolean is_empty = TRUE;
1641 guint pending_ops = 0;
1643 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1644 tmp = priv->progress_widgets;
1646 /* Check all observers */
1647 while (tmp && is_empty) {
1648 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1649 is_empty = pending_ops == 0;
1651 tmp = g_slist_next(tmp);
1658 on_account_removed (TnyAccountStore *account_store,
1659 TnyAccount *account,
1662 /* Do nothing if it's a transport account, because we only
1663 show the messages of a store account */
1664 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
1665 const gchar *parent_acc = NULL;
1666 const gchar *our_acc = NULL;
1668 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
1669 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
1671 /* Close this window if I'm showing a message of the removed account */
1672 if (strcmp (parent_acc, our_acc) == 0)
1673 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
1678 on_queue_changed (ModestMailOperationQueue *queue,
1679 ModestMailOperation *mail_op,
1680 ModestMailOperationQueueNotification type,
1681 ModestMsgViewWindow *self)
1684 ModestMsgViewWindowPrivate *priv;
1685 ModestMailOperationTypeOperation op_type;
1686 ModestToolBarModes mode;
1688 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1689 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1691 /* If this operations was created by another window, do nothing */
1692 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
1695 /* Get toolbar mode from operation id*/
1696 op_type = modest_mail_operation_get_type_operation (mail_op);
1698 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
1699 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1700 case MODEST_MAIL_OPERATION_TYPE_OPEN:
1701 mode = TOOLBAR_MODE_TRANSFER;
1704 mode = TOOLBAR_MODE_NORMAL;
1708 /* Add operation observers and change toolbar if neccessary*/
1709 tmp = priv->progress_widgets;
1711 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1712 if (mode == TOOLBAR_MODE_TRANSFER) {
1713 /* Enable transfer toolbar mode */
1714 set_toolbar_transfer_mode(self);
1716 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1718 tmp = g_slist_next (tmp);
1723 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1724 if (mode == TOOLBAR_MODE_TRANSFER) {
1726 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1728 tmp = g_slist_next (tmp);
1732 /* If no more operations are being observed, NORMAL mode is enabled again */
1733 if (observers_empty (self)) {
1734 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1742 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
1744 ModestMsgViewWindowPrivate *priv;
1745 GList *selected_attachments = NULL;
1747 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
1748 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
1750 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
1752 return selected_attachments;
1756 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
1758 ModestMsgViewWindowPrivate *priv;
1759 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1760 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
1762 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1764 if (mime_part == NULL) {
1765 gboolean error = FALSE;
1766 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
1767 if (selected_attachments == NULL) {
1769 } else if (g_list_length (selected_attachments) > 1) {
1770 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
1773 mime_part = (TnyMimePart *) selected_attachments->data;
1774 g_object_ref (mime_part);
1776 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
1777 g_list_free (selected_attachments);
1782 g_object_ref (mime_part);
1785 if (tny_mime_part_is_purged (mime_part)) {
1786 g_object_unref (mime_part);
1790 if (!TNY_IS_MSG (mime_part)) {
1791 gchar *filepath = NULL;
1792 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
1793 gchar *extension = NULL;
1794 TnyFsStream *temp_stream = NULL;
1797 extension = g_strrstr (att_filename, ".");
1798 if (extension != NULL)
1802 temp_stream = modest_maemo_utils_create_temp_stream (extension, &filepath);
1805 const gchar *content_type;
1806 content_type = tny_mime_part_get_content_type (mime_part);
1807 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
1809 modest_platform_activate_file (filepath, content_type);
1810 g_object_unref (temp_stream);
1812 /* TODO: delete temporary file */
1815 /* message attachment */
1816 TnyHeader *header = NULL;
1817 ModestWindowMgr *mgr;
1818 ModestWindow *msg_win = NULL;
1821 header = tny_msg_get_header (TNY_MSG (mime_part));
1822 mgr = modest_runtime_get_window_mgr ();
1823 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
1826 if (msg_win) /* there is already a window for this uid; top it */
1827 gtk_window_present (GTK_WINDOW(msg_win));
1829 /* if it's found, but there is no msg_win, it's probably in the process of being created;
1830 * thus, we don't do anything */
1831 g_warning ("window for is already being created");
1833 /* it's not found, so create a new window for it */
1834 modest_window_mgr_register_header (mgr, header); /* register the uid before building the window */
1835 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
1837 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
1838 msg_win = modest_msg_view_window_new (TNY_MSG (mime_part), account, NULL);
1839 modest_window_set_zoom (MODEST_WINDOW (msg_win),
1840 modest_window_get_zoom (MODEST_WINDOW (window)));
1841 modest_window_mgr_register_window (mgr, msg_win);
1842 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
1843 gtk_widget_show_all (GTK_WIDGET (msg_win));
1846 g_object_unref (mime_part);
1862 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
1863 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
1864 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
1865 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
1868 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
1872 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
1873 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
1874 g_free (pair->filename);
1875 g_object_unref (pair->part);
1876 g_slice_free (SaveMimePartPair, pair);
1878 g_list_free (info->pairs);
1881 gtk_widget_destroy (info->banner);
1882 g_object_unref (info->banner);
1883 g_slice_free (SaveMimePartInfo, info);
1888 idle_save_mime_part_show_result (SaveMimePartInfo *info)
1890 if (info->pairs != NULL) {
1891 gdk_threads_enter ();
1892 save_mime_parts_to_file_with_checks (info);
1893 gdk_threads_leave ();
1896 result = info->result;
1898 gdk_threads_enter ();
1899 save_mime_part_info_free (info, TRUE);
1901 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
1903 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
1905 gdk_threads_leave ();
1912 save_mime_part_to_file (SaveMimePartInfo *info)
1914 GnomeVFSResult result;
1915 GnomeVFSHandle *handle;
1917 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
1919 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0777);
1920 if (result == GNOME_VFS_OK) {
1921 stream = tny_vfs_stream_new (handle);
1922 tny_mime_part_decode_to_stream (pair->part, stream);
1923 g_object_unref (G_OBJECT (stream));
1924 g_object_unref (pair->part);
1925 g_slice_free (SaveMimePartPair, pair);
1926 info->pairs = g_list_delete_link (info->pairs, info->pairs);
1927 info->result = TRUE;
1929 save_mime_part_info_free (info, FALSE);
1930 info->result = FALSE;
1933 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
1938 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
1940 SaveMimePartPair *pair;
1941 gboolean is_ok = TRUE;
1943 pair = info->pairs->data;
1944 if (modest_maemo_utils_file_exists (pair->filename)) {
1945 GtkWidget *confirm_overwrite_dialog;
1946 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL,
1947 _("emev_nc_replace_files"));
1948 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
1951 gtk_widget_destroy (confirm_overwrite_dialog);
1955 save_mime_part_info_free (info, TRUE);
1957 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
1964 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
1966 gboolean clean_list = FALSE;
1967 ModestMsgViewWindowPrivate *priv;
1968 GList *files_to_save = NULL;
1969 GtkWidget *save_dialog = NULL;
1970 gchar *folder = NULL;
1971 gboolean canceled = FALSE;
1972 const gchar *filename = NULL;
1973 gchar *save_multiple_str = NULL;
1975 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1976 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1978 if (mime_parts == NULL) {
1979 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
1980 if (mime_parts == NULL)
1985 /* prepare dialog */
1986 if (mime_parts->next == NULL) {
1987 /* only one attachment selected */
1988 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
1989 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
1990 filename = tny_mime_part_get_filename (mime_part);
1992 g_warning ("Tried to save a non-file attachment");
1996 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
1997 g_list_length (mime_parts));
2000 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2001 GTK_FILE_CHOOSER_ACTION_SAVE);
2004 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2005 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2009 if (filename != NULL)
2010 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2013 /* if multiple, set multiple string */
2014 if (save_multiple_str) {
2015 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2019 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2020 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2022 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2023 hildon_banner_show_information
2024 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2028 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2029 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2031 if (tny_mime_part_is_attachment (mime_part)) {
2032 SaveMimePartPair *pair;
2034 if ((mime_parts->next != NULL) &&
2035 (tny_mime_part_get_filename (mime_part) == NULL))
2038 pair = g_slice_new0 (SaveMimePartPair);
2039 if (mime_parts->next == NULL) {
2040 pair->filename = g_strdup (chooser_uri);
2043 g_build_filename (chooser_uri,
2044 tny_mime_part_get_filename (mime_part), NULL);
2046 pair->part = g_object_ref (mime_part);
2047 files_to_save = g_list_prepend (files_to_save, pair);
2051 g_free (chooser_uri);
2054 gtk_widget_destroy (save_dialog);
2057 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2058 g_list_free (mime_parts);
2061 if (files_to_save != NULL) {
2062 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2063 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2064 _CS("sfil_ib_saving"));
2065 info->pairs = files_to_save;
2066 info->banner = banner;
2067 info->result = TRUE;
2068 g_object_ref (banner);
2069 save_mime_parts_to_file_with_checks (info);
2074 show_remove_attachment_information (gpointer userdata)
2076 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2077 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2079 if (priv->remove_attachment_banner != NULL) {
2080 gtk_widget_destroy (priv->remove_attachment_banner);
2081 g_object_unref (priv->remove_attachment_banner);
2084 priv->remove_attachment_banner = g_object_ref (
2085 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2091 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2093 ModestMsgViewWindowPrivate *priv;
2094 GList *mime_parts = NULL, *node;
2095 gchar *confirmation_message;
2099 /* TnyFolder *folder; */
2101 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2102 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2105 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2107 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2109 /* Remove already purged messages from mime parts list */
2111 while (node != NULL) {
2112 TnyMimePart *part = TNY_MIME_PART (node->data);
2113 if (tny_mime_part_is_purged (part)) {
2114 GList *deleted_node = node;
2115 node = g_list_next (node);
2116 g_object_unref (part);
2117 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2119 node = g_list_next (node);
2123 if (mime_parts == NULL)
2126 n_attachments = g_list_length (mime_parts);
2127 if (n_attachments == 1) {
2128 const gchar *filename;
2130 if (TNY_IS_MSG (mime_parts->data)) {
2132 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2133 filename = tny_header_get_subject (header);
2134 g_object_unref (header);
2135 if (filename == NULL)
2136 filename = _("mail_va_no_subject");
2138 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2140 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2142 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2143 "mcen_nc_purge_files_text",
2144 n_attachments), n_attachments);
2146 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2147 confirmation_message);
2148 g_free (confirmation_message);
2150 if (response != GTK_RESPONSE_OK)
2153 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2154 /* folder = tny_msg_get_folder (msg); */
2155 /* tny_msg_uncache_attachments (msg); */
2156 /* tny_folder_refresh (folder, NULL); */
2157 /* g_object_unref (folder); */
2159 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2160 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2161 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2164 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2165 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), NULL);
2166 tny_msg_rewrite_cache (msg);
2167 modest_msg_view_set_message (MODEST_MSG_VIEW (priv->msg_view), msg);
2169 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2170 g_list_free (mime_parts);
2172 if (priv->purge_timeout > 0) {
2173 g_source_remove (priv->purge_timeout);
2174 priv->purge_timeout = 0;
2177 if (priv->remove_attachment_banner) {
2178 gtk_widget_destroy (priv->remove_attachment_banner);
2179 g_object_unref (priv->remove_attachment_banner);
2180 priv->remove_attachment_banner = NULL;
2188 update_window_title (ModestMsgViewWindow *window)
2190 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2192 TnyHeader *header = NULL;
2193 const gchar *subject = NULL;
2195 msg = modest_msg_view_get_message (MODEST_MSG_VIEW (priv->msg_view));
2197 header = tny_msg_get_header (msg);
2198 subject = tny_header_get_subject (header);
2199 g_object_unref (msg);
2202 if ((subject == NULL)||(subject[0] == '\0'))
2203 subject = _("mail_va_no_subject");
2205 gtk_window_set_title (GTK_WINDOW (window), subject);