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 "modest-ui-dimming-manager.h"
54 #include <gdk/gdkkeysyms.h>
55 #include <modest-tny-account.h>
56 #include <modest-mime-part-view.h>
57 #include <modest-isearch-view.h>
60 #define DEFAULT_FOLDER "MyDocs/.documents"
62 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
63 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
64 static void modest_header_view_observer_init(
65 ModestHeaderViewObserverIface *iface_class);
66 static void modest_msg_view_window_finalize (GObject *obj);
67 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
69 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
70 ModestMsgViewWindow *obj);
71 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
72 ModestMsgViewWindow *obj);
74 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
75 static void modest_msg_view_window_set_zoom (ModestWindow *window,
77 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
78 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
79 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
80 static gboolean modest_msg_view_window_key_release_event (GtkWidget *window,
83 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
84 GdkEventWindowState *event,
86 static void modest_msg_view_window_scroll_up (ModestWindow *window);
87 static void modest_msg_view_window_scroll_down (ModestWindow *window);
88 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
90 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
91 gboolean show_toolbar);
93 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
95 ModestMsgViewWindow *window);
96 void modest_msg_view_window_on_row_changed(
97 GtkTreeModel *header_model,
100 ModestMsgViewWindow *window);
102 void modest_msg_view_window_on_row_deleted(
103 GtkTreeModel *header_model,
105 ModestMsgViewWindow *window);
107 void modest_msg_view_window_on_row_inserted(
108 GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 void modest_msg_view_window_on_row_reordered(
114 GtkTreeModel *header_model,
118 ModestMsgViewWindow *window);
120 void modest_msg_view_window_update_model_replaced(
121 ModestHeaderViewObserver *window,
123 const gchar *tny_folder_id);
125 static void cancel_progressbar (GtkToolButton *toolbutton,
126 ModestMsgViewWindow *self);
128 static void on_queue_changed (ModestMailOperationQueue *queue,
129 ModestMailOperation *mail_op,
130 ModestMailOperationQueueNotification type,
131 ModestMsgViewWindow *self);
133 static void on_account_removed (TnyAccountStore *account_store,
137 static void on_move_focus (ModestMsgViewWindow *window,
138 GtkDirectionType direction,
141 static void view_msg_cb (ModestMailOperation *mail_op,
148 static void set_toolbar_mode (ModestMsgViewWindow *self,
149 ModestToolBarModes mode);
151 static void update_window_title (ModestMsgViewWindow *window);
153 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
156 /* list my signals */
162 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
163 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
164 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
167 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
168 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
169 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
170 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
171 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
172 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
173 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
176 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
177 struct _ModestMsgViewWindowPrivate {
180 GtkWidget *main_scroll;
181 GtkWidget *find_toolbar;
184 /* Progress observers */
185 GtkWidget *progress_bar;
186 GSList *progress_widgets;
189 GtkWidget *progress_toolitem;
190 GtkWidget *cancel_toolitem;
191 GtkWidget *prev_toolitem;
192 GtkWidget *next_toolitem;
193 ModestToolBarModes current_toolbar_mode;
195 /* Optimized view enabled */
196 gboolean optimized_view;
198 /* Whether this was created via the *_new_for_search_result() function. */
199 gboolean is_search_result;
201 /* A reference to the @model of the header view
202 * to allow selecting previous/next messages,
203 * if the message is currently selected in the header view.
205 const gchar *header_folder_id;
206 GtkTreeModel *header_model;
207 GtkTreeRowReference *row_reference;
208 GtkTreeRowReference *next_row_reference;
210 gulong clipboard_change_handler;
211 gulong queue_change_handler;
212 gulong account_removed_handler;
213 gulong row_changed_handler;
214 gulong row_deleted_handler;
215 gulong row_inserted_handler;
216 gulong rows_reordered_handler;
219 GtkWidget *remove_attachment_banner;
221 guint progress_bar_timeout;
226 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
227 MODEST_TYPE_MSG_VIEW_WINDOW, \
228 ModestMsgViewWindowPrivate))
230 static GtkWindowClass *parent_class = NULL;
232 /* uncomment the following if you have defined any signals */
233 static guint signals[LAST_SIGNAL] = {0};
236 modest_msg_view_window_get_type (void)
238 static GType my_type = 0;
240 static const GTypeInfo my_info = {
241 sizeof(ModestMsgViewWindowClass),
242 NULL, /* base init */
243 NULL, /* base finalize */
244 (GClassInitFunc) modest_msg_view_window_class_init,
245 NULL, /* class finalize */
246 NULL, /* class data */
247 sizeof(ModestMsgViewWindow),
249 (GInstanceInitFunc) modest_msg_view_window_init,
252 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
253 "ModestMsgViewWindow",
256 static const GInterfaceInfo modest_header_view_observer_info =
258 (GInterfaceInitFunc) modest_header_view_observer_init,
259 NULL, /* interface_finalize */
260 NULL /* interface_data */
263 g_type_add_interface_static (my_type,
264 MODEST_TYPE_HEADER_VIEW_OBSERVER,
265 &modest_header_view_observer_info);
271 save_state (ModestWindow *self)
273 modest_widget_memory_save (modest_runtime_get_conf (),
275 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
280 restore_settings (ModestMsgViewWindow *self)
282 modest_widget_memory_restore (modest_runtime_get_conf (),
284 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
288 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
290 GObjectClass *gobject_class;
291 ModestWindowClass *modest_window_class;
292 gobject_class = (GObjectClass*) klass;
293 modest_window_class = (ModestWindowClass *) klass;
295 parent_class = g_type_class_peek_parent (klass);
296 gobject_class->finalize = modest_msg_view_window_finalize;
298 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
299 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
300 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
301 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
302 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
303 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
305 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
307 modest_window_class->save_state_func = save_state;
309 signals[MSG_CHANGED_SIGNAL] =
310 g_signal_new ("msg-changed",
311 G_TYPE_FROM_CLASS (gobject_class),
313 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
315 modest_marshal_VOID__POINTER_POINTER,
316 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
319 static void modest_header_view_observer_init(
320 ModestHeaderViewObserverIface *iface_class)
322 iface_class->update_func = modest_msg_view_window_update_model_replaced;
326 modest_msg_view_window_init (ModestMsgViewWindow *obj)
328 ModestMsgViewWindowPrivate *priv;
329 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
331 priv->is_search_result = FALSE;
333 priv->msg_view = NULL;
334 priv->header_model = NULL;
335 priv->header_folder_id = NULL;
336 priv->clipboard_change_handler = 0;
337 priv->queue_change_handler = 0;
338 priv->account_removed_handler = 0;
339 priv->row_changed_handler = 0;
340 priv->row_deleted_handler = 0;
341 priv->row_inserted_handler = 0;
342 priv->rows_reordered_handler = 0;
343 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
345 priv->optimized_view = FALSE;
346 priv->progress_bar_timeout = 0;
347 priv->purge_timeout = 0;
348 priv->remove_attachment_banner = NULL;
349 priv->msg_uid = NULL;
351 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
352 GTK_WINDOW(obj),"applications_email_viewer");
357 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
359 ModestMsgViewWindowPrivate *priv = NULL;
361 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
363 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
365 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
367 if (priv->progress_bar_timeout > 0) {
368 g_source_remove (priv->progress_bar_timeout);
369 priv->progress_bar_timeout = 0;
376 set_toolbar_mode (ModestMsgViewWindow *self,
377 ModestToolBarModes mode)
379 ModestWindowPrivate *parent_priv;
380 ModestMsgViewWindowPrivate *priv;
381 /* GtkWidget *widget = NULL; */
383 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
385 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
386 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
388 /* Sets current toolbar mode */
389 priv->current_toolbar_mode = mode;
391 /* Update toolbar dimming state */
392 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
395 case TOOLBAR_MODE_NORMAL:
396 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
397 /* gtk_action_set_sensitive (widget, TRUE); */
398 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
399 /* gtk_action_set_sensitive (widget, TRUE); */
400 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
401 /* gtk_action_set_sensitive (widget, TRUE); */
402 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
403 /* gtk_action_set_sensitive (widget, TRUE); */
405 if (priv->prev_toolitem)
406 gtk_widget_show (priv->prev_toolitem);
408 if (priv->next_toolitem)
409 gtk_widget_show (priv->next_toolitem);
411 if (priv->progress_toolitem)
412 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
413 if (priv->progress_bar)
414 gtk_widget_hide (priv->progress_bar);
416 if (priv->cancel_toolitem)
417 gtk_widget_hide (priv->cancel_toolitem);
419 /* Hide toolbar if optimized view is enabled */
420 if (priv->optimized_view) {
421 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
422 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
426 case TOOLBAR_MODE_TRANSFER:
427 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
428 /* gtk_action_set_sensitive (widget, FALSE); */
429 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
430 /* gtk_action_set_sensitive (widget, FALSE); */
431 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
432 /* gtk_action_set_sensitive (widget, FALSE); */
433 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
434 /* gtk_action_set_sensitive (widget, FALSE); */
436 if (priv->prev_toolitem)
437 gtk_widget_hide (priv->prev_toolitem);
439 if (priv->next_toolitem)
440 gtk_widget_hide (priv->next_toolitem);
442 if (priv->progress_toolitem)
443 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
444 if (priv->progress_bar)
445 gtk_widget_show (priv->progress_bar);
447 if (priv->cancel_toolitem)
448 gtk_widget_show (priv->cancel_toolitem);
450 /* Show toolbar if it's hiden (optimized view ) */
451 if (priv->optimized_view) {
452 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
453 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
458 g_return_if_reached ();
465 menubar_to_menu (GtkUIManager *ui_manager)
467 GtkWidget *main_menu;
469 GList *iter, *children;
471 /* Create new main menu */
472 main_menu = gtk_menu_new();
474 /* Get the menubar from the UI manager */
475 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
477 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
481 menu = GTK_WIDGET (iter->data);
482 gtk_widget_reparent(menu, main_menu);
484 iter = g_list_next (iter);
486 g_list_free (children);
492 init_window (ModestMsgViewWindow *obj)
494 GtkWidget *main_vbox;
495 ModestMsgViewWindowPrivate *priv;
496 ModestWindowPrivate *parent_priv;
498 GtkAction *action = NULL;
500 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
501 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
503 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
504 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
505 main_vbox = gtk_vbox_new (FALSE, 6);
508 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
509 conf = modest_runtime_get_conf ();
510 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
511 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
512 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
513 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
514 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
515 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
516 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
517 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
518 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
519 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
521 #ifdef MODEST_USE_MOZEMBED
522 priv->main_scroll = priv->msg_view;
523 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
525 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
526 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
528 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
529 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
530 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
532 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
533 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
535 priv->find_toolbar = hildon_find_toolbar_new (NULL);
536 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
537 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
538 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
539 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
541 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);
542 gtk_widget_show_all (GTK_WIDGET(main_vbox));
546 modest_msg_view_window_disconnect_signals (ModestWindow *self)
548 ModestMsgViewWindowPrivate *priv;
549 ModestHeaderView *header_view = NULL;
550 ModestWindow *main_window = NULL;
552 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
554 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
555 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
556 priv->clipboard_change_handler))
557 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
558 priv->clipboard_change_handler);
560 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
561 priv->queue_change_handler))
562 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
563 priv->queue_change_handler);
565 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
566 priv->account_removed_handler))
567 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
568 priv->account_removed_handler);
570 if (priv->header_model) {
571 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
572 priv->row_changed_handler))
573 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
574 priv->row_changed_handler);
576 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
577 priv->row_deleted_handler))
578 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
579 priv->row_deleted_handler);
581 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
582 priv->row_inserted_handler))
583 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
584 priv->row_inserted_handler);
586 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
587 priv->rows_reordered_handler))
588 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
589 priv->rows_reordered_handler);
592 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
593 FALSE); /* don't create */
597 header_view = MODEST_HEADER_VIEW(
598 modest_main_window_get_child_widget(
599 MODEST_MAIN_WINDOW(main_window),
600 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
601 if (header_view == NULL)
604 modest_header_view_remove_observer(header_view,
605 MODEST_HEADER_VIEW_OBSERVER(self));
609 modest_msg_view_window_finalize (GObject *obj)
611 ModestMsgViewWindowPrivate *priv;
613 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
615 /* Sanity check: shouldn't be needed, the window mgr should
616 call this function before */
617 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
619 if (priv->header_model != NULL) {
620 g_object_unref (priv->header_model);
621 priv->header_model = NULL;
624 if (priv->progress_bar_timeout > 0) {
625 g_source_remove (priv->progress_bar_timeout);
626 priv->progress_bar_timeout = 0;
629 if (priv->remove_attachment_banner) {
630 gtk_widget_destroy (priv->remove_attachment_banner);
631 g_object_unref (priv->remove_attachment_banner);
632 priv->remove_attachment_banner = NULL;
635 if (priv->purge_timeout > 0) {
636 g_source_remove (priv->purge_timeout);
637 priv->purge_timeout = 0;
640 if (priv->row_reference) {
641 gtk_tree_row_reference_free (priv->row_reference);
642 priv->row_reference = NULL;
645 if (priv->next_row_reference) {
646 gtk_tree_row_reference_free (priv->next_row_reference);
647 priv->next_row_reference = NULL;
651 g_free (priv->msg_uid);
652 priv->msg_uid = NULL;
655 G_OBJECT_CLASS(parent_class)->finalize (obj);
659 select_next_valid_row (GtkTreeModel *model,
660 GtkTreeRowReference **row_reference,
663 GtkTreeIter tmp_iter;
664 GtkTreePath *path, *next;
665 gboolean retval = FALSE;
667 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
669 path = gtk_tree_row_reference_get_path (*row_reference);
670 gtk_tree_model_get_iter (model, &tmp_iter, path);
671 gtk_tree_row_reference_free (*row_reference);
672 *row_reference = NULL;
674 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
675 next = gtk_tree_model_get_path (model, &tmp_iter);
676 *row_reference = gtk_tree_row_reference_new (model, next);
678 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
679 next = gtk_tree_model_get_path (model, &tmp_iter);
681 /* Ensure that we are not selecting the same */
682 if (gtk_tree_path_compare (path, next) != 0) {
683 *row_reference = gtk_tree_row_reference_new (model, next);
689 gtk_tree_path_free (path);
694 /* TODO: This should be in _init(), with the parameters as properties. */
696 modest_msg_view_window_construct (ModestMsgViewWindow *self,
697 const gchar *modest_account_name,
698 const gchar *msg_uid)
701 ModestMsgViewWindowPrivate *priv = NULL;
702 ModestWindowPrivate *parent_priv = NULL;
703 ModestDimmingRulesGroup *menu_rules_group = NULL;
704 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
705 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
706 GtkActionGroup *action_group = NULL;
707 GError *error = NULL;
708 GdkPixbuf *window_icon;
710 obj = G_OBJECT (self);
711 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
712 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
714 priv->msg_uid = g_strdup (msg_uid);
716 parent_priv->ui_manager = gtk_ui_manager_new();
717 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
719 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
720 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
722 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
723 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
724 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
726 /* Add common actions */
727 gtk_action_group_add_actions (action_group,
728 modest_action_entries,
729 G_N_ELEMENTS (modest_action_entries),
731 gtk_action_group_add_toggle_actions (action_group,
732 modest_toggle_action_entries,
733 G_N_ELEMENTS (modest_toggle_action_entries),
735 gtk_action_group_add_toggle_actions (action_group,
736 msg_view_toggle_action_entries,
737 G_N_ELEMENTS (msg_view_toggle_action_entries),
739 gtk_action_group_add_radio_actions (action_group,
740 msg_view_zoom_action_entries,
741 G_N_ELEMENTS (msg_view_zoom_action_entries),
743 G_CALLBACK (modest_ui_actions_on_change_zoom),
746 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
747 g_object_unref (action_group);
749 /* Load the UI definition */
750 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
753 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
754 g_error_free (error);
759 /* Add common dimming rules */
760 modest_dimming_rules_group_add_rules (menu_rules_group,
761 modest_msg_view_menu_dimming_entries,
762 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
763 MODEST_WINDOW (self));
764 modest_dimming_rules_group_add_rules (toolbar_rules_group,
765 modest_msg_view_toolbar_dimming_entries,
766 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
767 MODEST_WINDOW (self));
768 modest_dimming_rules_group_add_rules (clipboard_rules_group,
769 modest_msg_view_clipboard_dimming_entries,
770 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
771 MODEST_WINDOW (self));
773 /* Insert dimming rules group for this window */
774 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
775 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
776 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
777 g_object_unref (menu_rules_group);
778 g_object_unref (toolbar_rules_group);
779 g_object_unref (clipboard_rules_group);
781 /* Add accelerators */
782 gtk_window_add_accel_group (GTK_WINDOW (obj),
783 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
786 init_window (MODEST_MSG_VIEW_WINDOW(obj));
787 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
789 /* Set window icon */
790 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
792 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
793 g_object_unref (window_icon);
796 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
798 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
799 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
800 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
801 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
802 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
803 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
804 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
805 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
806 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
807 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
809 g_signal_connect (G_OBJECT (obj), "key-release-event",
810 G_CALLBACK (modest_msg_view_window_key_release_event),
813 g_signal_connect (G_OBJECT (obj), "window-state-event",
814 G_CALLBACK (modest_msg_view_window_window_state_event),
817 g_signal_connect (G_OBJECT (obj), "move-focus",
818 G_CALLBACK (on_move_focus), obj);
820 /* Mail Operation Queue */
821 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
823 G_CALLBACK (on_queue_changed),
826 /* Account manager */
827 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
829 G_CALLBACK(on_account_removed),
832 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
834 priv->last_search = NULL;
836 /* Init the clipboard actions dim status */
837 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
839 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
841 /* Check toolbar dimming rules */
842 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
843 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
847 /* FIXME: parameter checks */
849 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
850 const gchar *modest_account_name,
851 const gchar *msg_uid,
853 GtkTreeRowReference *row_reference)
855 ModestMsgViewWindow *window = NULL;
856 ModestMsgViewWindowPrivate *priv = NULL;
857 TnyFolder *header_folder = NULL;
858 ModestHeaderView *header_view = NULL;
859 ModestWindow *main_window = NULL;
861 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
862 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
864 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
866 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
868 /* Remember the message list's TreeModel so we can detect changes
869 * and change the list selection when necessary: */
871 main_window = modest_window_mgr_get_main_window(
872 modest_runtime_get_window_mgr(), FALSE); /* don't create */
874 g_warning ("%s: BUG: no main window", __FUNCTION__);
878 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
879 MODEST_MAIN_WINDOW(main_window),
880 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
881 if (header_view != NULL){
882 header_folder = modest_header_view_get_folder(header_view);
883 g_assert(header_folder != NULL);
884 priv->header_folder_id = tny_folder_get_id(header_folder);
885 g_assert(priv->header_folder_id != NULL);
886 g_object_unref(header_folder);
889 priv->header_model = g_object_ref(model);
890 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
891 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
892 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
894 priv->row_changed_handler = g_signal_connect(
895 GTK_TREE_MODEL(model), "row-changed",
896 G_CALLBACK(modest_msg_view_window_on_row_changed),
898 priv->row_deleted_handler = g_signal_connect(
899 GTK_TREE_MODEL(model), "row-deleted",
900 G_CALLBACK(modest_msg_view_window_on_row_deleted),
902 priv->row_inserted_handler = g_signal_connect (
903 GTK_TREE_MODEL(model), "row-inserted",
904 G_CALLBACK(modest_msg_view_window_on_row_inserted),
906 priv->rows_reordered_handler = g_signal_connect(
907 GTK_TREE_MODEL(model), "rows-reordered",
908 G_CALLBACK(modest_msg_view_window_on_row_reordered),
911 if (header_view != NULL){
912 modest_header_view_add_observer(header_view,
913 MODEST_HEADER_VIEW_OBSERVER(window));
916 gtk_widget_show_all (GTK_WIDGET (window));
918 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
919 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
921 modest_msg_view_window_update_priority (window);
923 /* Check toolbar dimming rules */
924 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
926 return MODEST_WINDOW(window);
930 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
931 const gchar *modest_account_name,
932 const gchar *msg_uid)
934 ModestMsgViewWindow *window = NULL;
935 ModestMsgViewWindowPrivate *priv = NULL;
937 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
938 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
939 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
941 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
943 /* Remember that this is a search result,
944 * so we can disable some UI appropriately: */
945 priv->is_search_result = TRUE;
947 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
949 return MODEST_WINDOW(window);
953 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
954 const gchar *modest_account_name,
955 const gchar *msg_uid)
958 ModestMsgViewWindowPrivate *priv;
959 g_return_val_if_fail (msg, NULL);
961 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
962 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
963 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
964 modest_account_name, msg_uid);
966 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
968 return MODEST_WINDOW(obj);
971 void modest_msg_view_window_on_row_changed(
972 GtkTreeModel *header_model,
975 ModestMsgViewWindow *window){
976 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
979 void modest_msg_view_window_on_row_deleted(
980 GtkTreeModel *header_model,
982 ModestMsgViewWindow *window){
983 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
986 /* On insertions we check if the folder still has the message we are
987 * showing or do not. If do not, we do nothing. Which means we are still
988 * not attached to any header folder and thus next/prev buttons are
989 * still dimmed. Once the message that is shown by msg-view is found, the
990 * new model of header-view will be attached and the references will be set.
991 * On each further insertions dimming rules will be checked. However
992 * this requires extra CPU time at least works.
993 * (An message might be deleted from TnyFolder and thus will not be
994 * inserted into the model again for example if it is removed by the
995 * imap server and the header view is refreshed.)
997 void modest_msg_view_window_on_row_inserted(
998 GtkTreeModel *new_model,
999 GtkTreePath *tree_path,
1000 GtkTreeIter *tree_iter,
1001 ModestMsgViewWindow *window){
1002 ModestMsgViewWindowPrivate *priv = NULL;
1003 TnyHeader *header = NULL;
1006 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1008 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1010 /* If we already has a model attached then the message shown by
1011 * msg-view is in it, and thus we do not need any actions but
1012 * to check the dimming rules.*/
1013 if(priv->header_model != NULL){
1014 gtk_tree_row_reference_free(priv->next_row_reference);
1015 priv->next_row_reference = gtk_tree_row_reference_copy(
1016 priv->row_reference);
1017 select_next_valid_row (priv->header_model,
1018 &(priv->next_row_reference), FALSE);
1019 modest_ui_actions_check_toolbar_dimming_rules (
1020 MODEST_WINDOW (window));
1024 /* Check if the newly inserted message is the same we are actually
1025 * showing. IF not, we should remain detached from the header model
1026 * and thus prev and next toolbarbuttons should remain dimmed. */
1027 gtk_tree_model_get (new_model, tree_iter,
1028 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1029 uid = modest_tny_folder_get_header_unique_id(header);
1030 if(!g_str_equal(priv->msg_uid, uid)){
1036 /* Setup row_reference for the actual msg. */
1037 priv->row_reference = gtk_tree_row_reference_new(
1038 new_model, tree_path);
1039 if(priv->row_reference == NULL){
1040 g_warning("No reference for msg header item.");
1044 /* Attach new_model and connect some callback to it to become able
1045 * to detect changes in header-view. */
1046 priv->header_model = g_object_ref(new_model);
1047 g_signal_connect (new_model, "row-changed",
1048 G_CALLBACK (modest_msg_view_window_on_row_changed),
1050 g_signal_connect (new_model, "row-deleted",
1051 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1053 g_signal_connect (new_model, "rows-reordered",
1054 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1057 /* Now set up next_row_reference. */
1058 priv->next_row_reference = gtk_tree_row_reference_copy(
1059 priv->row_reference);
1060 select_next_valid_row (priv->header_model,
1061 &(priv->next_row_reference), FALSE);
1063 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1066 void modest_msg_view_window_on_row_reordered(
1067 GtkTreeModel *header_model,
1071 ModestMsgViewWindow *window){
1072 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1075 /* The modest_msg_view_window_update_model_replaced implements update
1076 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1077 * actually belongs to the header-view is the same as the TnyFolder of
1078 * the message of msg-view or not. If they are different, there is
1079 * nothing to do. If they are the same, then the model has replaced and
1080 * the reference in msg-view shall be replaced from the old model to
1081 * the new model. In this case the view will be detached from it's
1082 * header folder. From this point the next/prev buttons are dimmed.
1084 void modest_msg_view_window_update_model_replaced(
1085 ModestHeaderViewObserver *observer,
1086 GtkTreeModel *model,
1087 const gchar *tny_folder_id){
1088 ModestMsgViewWindowPrivate *priv = NULL;
1089 ModestMsgViewWindow *window = NULL;
1091 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1092 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1094 window = MODEST_MSG_VIEW_WINDOW(observer);
1095 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1097 /* If there is an other folder in the header-view then we do
1098 * not care about it's model (msg list). Else if the
1099 * header-view shows the folder the msg shown by us is in, we
1100 * shall replace our model reference and make some check. */
1101 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1104 /* Model is changed(replaced), so we should forget the old
1105 * one. Because there might be other references and there
1106 * might be some change on the model even if we unreferenced
1107 * it, we need to disconnect our signals here. */
1108 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1109 priv->row_changed_handler))
1110 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1111 priv->row_changed_handler);
1112 priv->row_changed_handler = 0;
1113 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1114 priv->row_deleted_handler))
1115 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1116 priv->row_deleted_handler);
1117 priv->row_deleted_handler = 0;
1118 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1119 priv->row_inserted_handler))
1120 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1121 priv->row_inserted_handler);
1122 priv->row_inserted_handler = 0;
1123 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1124 priv->rows_reordered_handler))
1125 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1126 priv->rows_reordered_handler);
1127 priv->rows_reordered_handler = 0;
1128 g_object_unref(priv->header_model);
1129 priv->header_model = NULL;
1130 g_object_unref(priv->row_reference);
1131 priv->row_reference = NULL;
1132 g_object_unref(priv->next_row_reference);
1133 priv->next_row_reference = NULL;
1135 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1137 g_assert(model != NULL);
1139 /* Also we must connect to the new model for row insertions.
1140 * Only for insertions now. We will need other ones only after
1141 * the msg is show by msg-view is added to the new model. */
1142 priv->row_inserted_handler = g_signal_connect (
1143 model, "row-inserted",
1144 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1149 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1151 ModestMsgViewWindowPrivate *priv= NULL;
1153 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1154 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1156 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1160 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1162 ModestMsgViewWindowPrivate *priv= NULL;
1164 TnyHeader *header = NULL;
1165 GtkTreePath *path = NULL;
1168 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1169 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1171 /* If the message was not obtained from a treemodel,
1172 * for instance if it was opened directly by the search UI:
1174 if (priv->header_model == NULL) {
1175 msg = modest_msg_view_window_get_message (self);
1177 header = tny_msg_get_header (msg);
1178 g_object_unref (msg);
1183 /* Get iter of the currently selected message in the header view: */
1184 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1185 * instead of sometimes retrieving it from the header view?
1186 * Then we wouldn't be dependent on the message actually still being selected
1187 * in the header view. murrayc. */
1188 if (!gtk_tree_row_reference_valid (priv->row_reference))
1190 path = gtk_tree_row_reference_get_path (priv->row_reference);
1191 g_return_val_if_fail (path != NULL, NULL);
1192 gtk_tree_model_get_iter (priv->header_model,
1196 /* Get current message header */
1197 gtk_tree_model_get (priv->header_model, &iter,
1198 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1201 gtk_tree_path_free (path);
1206 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1208 ModestMsgViewWindowPrivate *priv;
1210 g_return_val_if_fail (self, NULL);
1212 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1214 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1218 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1220 ModestMsgViewWindowPrivate *priv;
1222 g_return_val_if_fail (self, NULL);
1224 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1226 return (const gchar*) priv->msg_uid;
1230 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1233 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1234 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1235 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1239 is_active = gtk_toggle_action_get_active (toggle);
1242 gtk_widget_show (priv->find_toolbar);
1243 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1245 gtk_widget_hide (priv->find_toolbar);
1248 /* update the toggle buttons status */
1249 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1250 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1251 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1252 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1257 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1258 ModestMsgViewWindow *obj)
1260 GtkToggleAction *toggle;
1261 ModestWindowPrivate *parent_priv;
1262 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1264 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1265 gtk_toggle_action_set_active (toggle, FALSE);
1269 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1270 ModestMsgViewWindow *obj)
1272 gchar *current_search;
1273 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1275 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1276 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1280 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1282 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1283 g_free (current_search);
1284 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1288 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1290 g_free (priv->last_search);
1291 priv->last_search = g_strdup (current_search);
1292 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1295 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1296 g_free (priv->last_search);
1297 priv->last_search = NULL;
1299 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1302 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1303 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1304 g_free (priv->last_search);
1305 priv->last_search = NULL;
1307 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1311 g_free (current_search);
1316 modest_msg_view_window_set_zoom (ModestWindow *window,
1319 ModestMsgViewWindowPrivate *priv;
1320 ModestWindowPrivate *parent_priv;
1321 GtkAction *action = NULL;
1322 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1324 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1326 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1327 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1328 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1331 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1333 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1337 modest_msg_view_window_get_zoom (ModestWindow *window)
1339 ModestMsgViewWindowPrivate *priv;
1341 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1343 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1344 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1348 modest_msg_view_window_zoom_plus (ModestWindow *window)
1350 ModestWindowPrivate *parent_priv;
1351 GtkRadioAction *zoom_radio_action;
1352 GSList *group, *node;
1354 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1355 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1356 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1358 group = gtk_radio_action_get_group (zoom_radio_action);
1360 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1361 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1365 for (node = group; node != NULL; node = g_slist_next (node)) {
1366 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1367 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1375 modest_msg_view_window_zoom_minus (ModestWindow *window)
1377 ModestWindowPrivate *parent_priv;
1378 GtkRadioAction *zoom_radio_action;
1379 GSList *group, *node;
1381 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1382 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1383 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1385 group = gtk_radio_action_get_group (zoom_radio_action);
1387 for (node = group; node != NULL; node = g_slist_next (node)) {
1388 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1389 if (node->next != NULL) {
1390 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1393 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1403 modest_msg_view_window_key_release_event (GtkWidget *window,
1407 if (event->type == GDK_KEY_RELEASE) {
1408 switch (event->keyval) {
1410 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1414 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1427 modest_msg_view_window_scroll_up (ModestWindow *window)
1429 ModestMsgViewWindowPrivate *priv;
1430 gboolean return_value;
1432 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1433 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1437 modest_msg_view_window_scroll_down (ModestWindow *window)
1439 ModestMsgViewWindowPrivate *priv;
1440 gboolean return_value;
1442 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1443 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1447 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1450 ModestMsgViewWindowPrivate *priv;
1451 GtkTreeIter tmp_iter;
1452 gboolean is_last_selected;
1454 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1455 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1457 /*if no model (so no rows at all), then virtually we are the last*/
1458 if (!priv->header_model)
1461 path = gtk_tree_row_reference_get_path (priv->row_reference);
1465 is_last_selected = TRUE;
1466 while (is_last_selected) {
1468 gtk_tree_path_next (path);
1469 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1471 gtk_tree_model_get (priv->header_model, &tmp_iter,
1472 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1474 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1475 is_last_selected = FALSE;
1477 gtk_tree_path_free (path);
1478 return is_last_selected;
1482 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1484 ModestMsgViewWindowPrivate *priv;
1486 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1487 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1489 return priv->header_model != NULL;
1493 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1495 ModestMsgViewWindowPrivate *priv;
1497 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1498 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1500 return priv->is_search_result;
1504 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1507 ModestMsgViewWindowPrivate *priv;
1508 gboolean is_first_selected;
1509 GtkTreeIter tmp_iter;
1510 /* gchar * path_string;*/
1512 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1513 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1515 /*if no model (so no rows at all), then virtually we are the first*/
1516 if (!priv->header_model)
1519 path = gtk_tree_row_reference_get_path (priv->row_reference);
1523 /* path_string = gtk_tree_path_to_string (path);
1524 is_first_selected = strcmp (path_string, "0");
1526 g_free (path_string);
1527 gtk_tree_path_free (path);
1529 return is_first_selected;*/
1531 is_first_selected = TRUE;
1532 while (is_first_selected) {
1534 if(!gtk_tree_path_prev (path))
1536 /* Here the 'if' is needless for logic, but let make sure
1537 * iter is valid for gtk_tree_model_get. */
1538 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1540 gtk_tree_model_get (priv->header_model, &tmp_iter,
1541 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1543 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1544 is_first_selected = FALSE;
1546 gtk_tree_path_free (path);
1547 return is_first_selected;
1551 * Reads the message whose summary item is @header. It takes care of
1552 * several things, among others:
1554 * If the message was not previously downloaded then ask the user
1555 * before downloading. If there is no connection launch the connection
1556 * dialog. Update toolbar dimming rules.
1558 * Returns: TRUE if the mail operation was started, otherwise if the
1559 * user do not want to download the message, or if the user do not
1560 * want to connect, then the operation is not issued
1563 message_reader (ModestMsgViewWindow *window,
1564 ModestMsgViewWindowPrivate *priv,
1566 GtkTreeRowReference *row_reference)
1568 ModestMailOperation *mail_op = NULL;
1569 ModestMailOperationTypeOperation op_type;
1570 gboolean already_showing = FALSE;
1571 ModestWindow *msg_window = NULL;
1572 ModestWindowMgr *mgr;
1574 g_return_val_if_fail (row_reference != NULL, FALSE);
1576 mgr = modest_runtime_get_window_mgr ();
1577 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1578 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1581 gtk_window_present (GTK_WINDOW (msg_window));
1582 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1586 /* Msg download completed */
1587 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1588 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1590 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1592 /* Ask the user if he wants to download the message if
1594 if (!tny_device_is_online (modest_runtime_get_device())) {
1595 TnyFolder *folder = NULL;
1596 GtkResponseType response;
1598 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1599 _("mcen_nc_get_msg"));
1600 if (response == GTK_RESPONSE_CANCEL)
1603 /* Offer the connection dialog if necessary */
1604 folder = tny_header_get_folder (header);
1606 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1607 TNY_FOLDER_STORE (folder))) {
1608 g_object_unref (folder);
1611 g_object_unref (folder);
1616 /* New mail operation */
1617 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1618 modest_ui_actions_get_msgs_full_error_handler,
1621 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1622 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1623 g_object_unref (mail_op);
1625 /* Update toolbar dimming rules */
1626 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1632 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1634 ModestMsgViewWindowPrivate *priv;
1635 GtkTreePath *path= NULL;
1636 GtkTreeIter tmp_iter;
1638 gboolean retval = TRUE;
1639 GtkTreeRowReference *row_reference = NULL;
1641 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1642 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1644 /* Update the next row reference if it's not valid. This could
1645 happen if for example the header which it was pointing to,
1646 was deleted. The best place to do it is in the row-deleted
1647 handler but the tinymail model do not work like the glib
1648 tree models and reports the deletion when the row is still
1650 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1651 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1652 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1653 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1656 if (priv->next_row_reference)
1657 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1661 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1663 gtk_tree_model_get_iter (priv->header_model,
1666 gtk_tree_path_free (path);
1668 gtk_tree_model_get (priv->header_model, &tmp_iter,
1669 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1672 /* Read the message & show it */
1673 if (!message_reader (window, priv, header, row_reference)) {
1675 gtk_tree_row_reference_free (row_reference);
1679 g_object_unref (header);
1685 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1687 ModestMsgViewWindowPrivate *priv = NULL;
1688 TnyHeader *header = NULL;
1690 GtkTreePath *path = NULL;
1691 GtkTreeRowReference *row_reference = NULL;
1693 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1694 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1696 /* Check that the model is not empty */
1697 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1700 /* Get the header */
1701 gtk_tree_model_get (priv->header_model,
1703 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1705 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1706 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1707 g_object_unref (header);
1708 return modest_msg_view_window_select_next_message (self);
1711 path = gtk_tree_model_get_path (priv->header_model, &iter);
1712 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1713 gtk_tree_path_free (path);
1715 /* Read the message & show it */
1716 message_reader (self, priv, header, row_reference);
1719 g_object_unref (header);
1725 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1727 ModestMsgViewWindowPrivate *priv = NULL;
1729 GtkTreeRowReference *row_reference = NULL;
1731 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1732 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1734 /* Return inmediatly if there is no header model */
1735 if (!priv->header_model)
1738 path = gtk_tree_row_reference_get_path (priv->row_reference);
1739 while (gtk_tree_path_prev (path)) {
1743 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1744 gtk_tree_model_get (priv->header_model, &iter,
1745 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1749 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1750 g_object_unref (header);
1754 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1755 /* Read the message & show it */
1756 if (!message_reader (window, priv, header, row_reference)) {
1757 gtk_tree_row_reference_free (row_reference);
1758 g_object_unref (header);
1762 gtk_tree_path_free (path);
1763 g_object_unref (header);
1768 gtk_tree_path_free (path);
1773 view_msg_cb (ModestMailOperation *mail_op,
1780 ModestMsgViewWindow *self = NULL;
1781 ModestMsgViewWindowPrivate *priv = NULL;
1782 GtkTreeRowReference *row_reference = NULL;
1784 /* If there was any error */
1785 row_reference = (GtkTreeRowReference *) user_data;
1786 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1787 gtk_tree_row_reference_free (row_reference);
1791 /* Get the window */
1792 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1793 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1794 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1796 /* Update the row reference */
1797 gtk_tree_row_reference_free (priv->row_reference);
1798 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1799 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1800 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1801 gtk_tree_row_reference_free (row_reference);
1803 /* Mark header as read */
1804 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1805 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1807 /* Set new message */
1808 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1809 modest_msg_view_window_update_priority (self);
1810 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1811 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1813 /* Set the new message uid of the window */
1814 if (priv->msg_uid) {
1815 g_free (priv->msg_uid);
1816 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1819 /* Notify the observers */
1820 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1821 0, priv->header_model, priv->row_reference);
1823 /* Free new references */
1824 g_object_unref (self);
1828 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1830 ModestMsgViewWindowPrivate *priv;
1832 TnyFolderType folder_type;
1834 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1836 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1838 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1842 folder = tny_msg_get_folder (msg);
1844 folder_type = tny_folder_get_folder_type (folder);
1845 g_object_unref (folder);
1847 g_object_unref (msg);
1855 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1857 ModestMsgViewWindowPrivate *priv;
1858 TnyHeaderFlags flags = 0;
1860 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1862 if (priv->header_model) {
1865 GtkTreePath *path = NULL;
1867 path = gtk_tree_row_reference_get_path (priv->row_reference);
1868 g_return_if_fail (path != NULL);
1869 gtk_tree_model_get_iter (priv->header_model,
1871 gtk_tree_row_reference_get_path (priv->row_reference));
1873 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1875 flags = tny_header_get_flags (header);
1876 gtk_tree_path_free (path);
1879 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1884 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1886 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1887 ModestWindowPrivate *parent_priv;
1888 ModestWindowMgr *mgr;
1889 gboolean is_fullscreen;
1890 GtkAction *fs_toggle_action;
1893 mgr = modest_runtime_get_window_mgr ();
1894 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1896 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1898 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1899 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1900 if (is_fullscreen != active) {
1901 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1910 set_homogeneous (GtkWidget *widget,
1913 if (GTK_IS_TOOL_ITEM (widget)) {
1914 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1915 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1920 modest_msg_view_window_show_toolbar (ModestWindow *self,
1921 gboolean show_toolbar)
1923 ModestMsgViewWindowPrivate *priv = NULL;
1924 ModestWindowPrivate *parent_priv;
1925 GtkWidget *reply_button = NULL, *menu = NULL;
1926 GtkWidget *placeholder = NULL;
1928 const gchar *action_name;
1931 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1932 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1934 /* Set optimized view status */
1935 priv->optimized_view = !show_toolbar;
1937 if (!parent_priv->toolbar) {
1938 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1940 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1942 /* Set homogeneous toolbar */
1943 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1944 set_homogeneous, NULL);
1946 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1947 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1948 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1949 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1950 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1951 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1952 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1953 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1955 /* Add ProgressBar (Transfer toolbar) */
1956 priv->progress_bar = modest_progress_bar_widget_new ();
1957 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1958 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1959 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1960 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1961 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1963 /* Connect cancel 'clicked' signal to abort progress mode */
1964 g_signal_connect(priv->cancel_toolitem, "clicked",
1965 G_CALLBACK(cancel_progressbar),
1968 /* Add it to the observers list */
1969 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1972 hildon_window_add_toolbar (HILDON_WINDOW (self),
1973 GTK_TOOLBAR (parent_priv->toolbar));
1976 /* Set reply button tap and hold menu */
1977 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1978 "/ToolBar/ToolbarMessageReply");
1979 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1980 "/ToolbarReplyCSM");
1981 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1985 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1986 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1987 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1989 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1990 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1993 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1994 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1997 /* Update also the actions (to update the toggles in the
1998 menus), we have to do it manually because some other window
1999 of the same time could have changed it (remember that the
2000 toolbar fullscreen mode is shared by all the windows of the
2002 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2003 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2005 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2007 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2008 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2013 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2015 ModestMsgViewWindow *window)
2017 if (!GTK_WIDGET_VISIBLE (window))
2020 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2024 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2026 ModestMsgViewWindowPrivate *priv;
2028 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2029 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2031 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2035 cancel_progressbar (GtkToolButton *toolbutton,
2036 ModestMsgViewWindow *self)
2039 ModestMsgViewWindowPrivate *priv;
2041 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2043 /* Get operation observers and cancel its current operation */
2044 tmp = priv->progress_widgets;
2046 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2047 tmp=g_slist_next(tmp);
2051 observers_empty (ModestMsgViewWindow *self)
2054 ModestMsgViewWindowPrivate *priv;
2055 gboolean is_empty = TRUE;
2056 guint pending_ops = 0;
2058 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2059 tmp = priv->progress_widgets;
2061 /* Check all observers */
2062 while (tmp && is_empty) {
2063 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2064 is_empty = pending_ops == 0;
2066 tmp = g_slist_next(tmp);
2073 on_account_removed (TnyAccountStore *account_store,
2074 TnyAccount *account,
2077 /* Do nothing if it's a transport account, because we only
2078 show the messages of a store account */
2079 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2080 const gchar *parent_acc = NULL;
2081 const gchar *our_acc = NULL;
2083 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2084 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2086 /* Close this window if I'm showing a message of the removed account */
2087 if (strcmp (parent_acc, our_acc) == 0)
2088 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2093 on_queue_changed (ModestMailOperationQueue *queue,
2094 ModestMailOperation *mail_op,
2095 ModestMailOperationQueueNotification type,
2096 ModestMsgViewWindow *self)
2099 ModestMsgViewWindowPrivate *priv;
2100 ModestMailOperationTypeOperation op_type;
2101 ModestToolBarModes mode;
2103 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2104 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2106 /* If this operations was created by another window, do nothing */
2107 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2110 /* Get toolbar mode from operation id*/
2111 op_type = modest_mail_operation_get_type_operation (mail_op);
2113 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2114 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2115 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2116 mode = TOOLBAR_MODE_TRANSFER;
2119 mode = TOOLBAR_MODE_NORMAL;
2123 /* Add operation observers and change toolbar if neccessary*/
2124 tmp = priv->progress_widgets;
2126 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2127 if (mode == TOOLBAR_MODE_TRANSFER) {
2128 /* Enable transfer toolbar mode */
2129 set_toolbar_transfer_mode(self);
2131 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2133 tmp = g_slist_next (tmp);
2138 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2139 if (mode == TOOLBAR_MODE_TRANSFER) {
2141 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2143 tmp = g_slist_next (tmp);
2147 /* If no more operations are being observed, NORMAL mode is enabled again */
2148 if (observers_empty (self)) {
2149 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2157 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2159 ModestMsgViewWindowPrivate *priv;
2160 GList *selected_attachments = NULL;
2162 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2163 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2165 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2167 return selected_attachments;
2171 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2173 ModestMsgViewWindowPrivate *priv;
2174 const gchar *msg_uid;
2175 gchar *attachment_uid = NULL;
2176 gint attachment_index = 0;
2179 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2180 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2181 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2183 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2184 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2185 attachment_index = g_list_index (attachments, mime_part);
2186 g_list_free (attachments);
2188 if (msg_uid && attachment_index >= 0) {
2189 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2192 if (mime_part == NULL) {
2193 gboolean error = FALSE;
2194 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2195 if (selected_attachments == NULL) {
2197 } else if (g_list_length (selected_attachments) > 1) {
2198 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2201 mime_part = (TnyMimePart *) selected_attachments->data;
2202 g_object_ref (mime_part);
2204 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2205 g_list_free (selected_attachments);
2210 g_object_ref (mime_part);
2213 if (tny_mime_part_is_purged (mime_part)) {
2214 g_object_unref (mime_part);
2218 if (!TNY_IS_MSG (mime_part)) {
2219 gchar *filepath = NULL;
2220 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2221 TnyFsStream *temp_stream = NULL;
2222 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2225 const gchar *content_type;
2226 content_type = tny_mime_part_get_content_type (mime_part);
2227 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2229 modest_platform_activate_file (filepath, content_type);
2230 g_object_unref (temp_stream);
2232 /* NOTE: files in the temporary area will be automatically
2233 * cleaned after some time if they are no longer in use */
2236 /* message attachment */
2237 TnyHeader *header = NULL;
2238 ModestWindowMgr *mgr;
2239 ModestWindow *msg_win = NULL;
2242 header = tny_msg_get_header (TNY_MSG (mime_part));
2243 mgr = modest_runtime_get_window_mgr ();
2244 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2247 if (msg_win) /* there is already a window for this uid; top it */
2248 gtk_window_present (GTK_WINDOW(msg_win));
2250 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2251 * thus, we don't do anything */
2252 g_warning ("window for is already being created");
2254 /* it's not found, so create a new window for it */
2255 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2256 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2258 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2259 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2260 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2261 modest_window_get_zoom (MODEST_WINDOW (window)));
2262 modest_window_mgr_register_window (mgr, msg_win);
2263 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2264 gtk_widget_show_all (GTK_WIDGET (msg_win));
2267 g_object_unref (mime_part);
2283 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2284 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2285 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2286 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2289 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2293 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2294 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2295 g_free (pair->filename);
2296 g_object_unref (pair->part);
2297 g_slice_free (SaveMimePartPair, pair);
2299 g_list_free (info->pairs);
2302 gtk_widget_destroy (info->banner);
2303 g_object_unref (info->banner);
2304 g_slice_free (SaveMimePartInfo, info);
2309 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2311 if (info->pairs != NULL) {
2312 save_mime_part_to_file (info);
2315 result = info->result;
2317 /* This is a GDK lock because we are an idle callback and
2318 * hildon_banner_show_information is or does Gtk+ code */
2320 gdk_threads_enter (); /* CHECKED */
2321 save_mime_part_info_free (info, TRUE);
2323 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2325 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2327 gdk_threads_leave (); /* CHECKED */
2334 save_mime_part_to_file (SaveMimePartInfo *info)
2336 GnomeVFSResult result;
2337 GnomeVFSHandle *handle;
2339 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2341 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0444);
2342 if (result == GNOME_VFS_OK) {
2343 stream = tny_vfs_stream_new (handle);
2344 tny_mime_part_decode_to_stream (pair->part, stream);
2345 g_object_unref (G_OBJECT (stream));
2346 g_object_unref (pair->part);
2347 g_slice_free (SaveMimePartPair, pair);
2348 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2349 info->result = TRUE;
2351 save_mime_part_info_free (info, FALSE);
2352 info->result = FALSE;
2355 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2360 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2362 gboolean is_ok = TRUE;
2363 gint replaced_files = 0;
2364 const GList *files = info->pairs;
2367 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2368 SaveMimePartPair *pair = iter->data;
2369 if (modest_maemo_utils_file_exists (pair->filename)) {
2373 if (replaced_files) {
2374 GtkWidget *confirm_overwrite_dialog;
2375 const gchar *message = (replaced_files == 1) ?
2376 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2377 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2378 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2381 gtk_widget_destroy (confirm_overwrite_dialog);
2385 save_mime_part_info_free (info, TRUE);
2387 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2388 _CS("sfil_ib_saving"));
2389 info->banner = g_object_ref (banner);
2390 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2391 g_object_unref (banner);
2398 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2400 gboolean clean_list = FALSE;
2401 ModestMsgViewWindowPrivate *priv;
2402 GList *files_to_save = NULL;
2403 GtkWidget *save_dialog = NULL;
2404 gchar *folder = NULL;
2405 gboolean canceled = FALSE;
2406 const gchar *filename = NULL;
2407 gchar *save_multiple_str = NULL;
2409 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2410 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2412 if (mime_parts == NULL) {
2413 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2414 if (mime_parts == NULL)
2419 /* prepare dialog */
2420 if (mime_parts->next == NULL) {
2421 /* only one attachment selected */
2422 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2423 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2424 filename = tny_mime_part_get_filename (mime_part);
2426 g_warning ("Tried to save a non-file attachment");
2430 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2431 g_list_length (mime_parts));
2434 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2435 GTK_FILE_CHOOSER_ACTION_SAVE);
2438 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2439 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2443 if (filename != NULL)
2444 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2447 /* if multiple, set multiple string */
2448 if (save_multiple_str) {
2449 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2453 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2454 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2456 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2457 hildon_banner_show_information
2458 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2462 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2463 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2465 if (tny_mime_part_is_attachment (mime_part)) {
2466 SaveMimePartPair *pair;
2468 if ((mime_parts->next != NULL) &&
2469 (tny_mime_part_get_filename (mime_part) == NULL))
2472 pair = g_slice_new0 (SaveMimePartPair);
2473 if (mime_parts->next == NULL) {
2474 pair->filename = g_strdup (chooser_uri);
2477 g_build_filename (chooser_uri,
2478 tny_mime_part_get_filename (mime_part), NULL);
2480 pair->part = g_object_ref (mime_part);
2481 files_to_save = g_list_prepend (files_to_save, pair);
2485 g_free (chooser_uri);
2488 gtk_widget_destroy (save_dialog);
2491 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2492 g_list_free (mime_parts);
2495 if (files_to_save != NULL) {
2496 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2497 info->pairs = files_to_save;
2498 info->result = TRUE;
2499 save_mime_parts_to_file_with_checks (info);
2504 show_remove_attachment_information (gpointer userdata)
2506 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2507 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2509 /* We're outside the main lock */
2510 gdk_threads_enter ();
2512 if (priv->remove_attachment_banner != NULL) {
2513 gtk_widget_destroy (priv->remove_attachment_banner);
2514 g_object_unref (priv->remove_attachment_banner);
2517 priv->remove_attachment_banner = g_object_ref (
2518 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2520 gdk_threads_leave ();
2526 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2528 ModestMsgViewWindowPrivate *priv;
2529 GList *mime_parts = NULL, *node;
2530 gchar *confirmation_message;
2534 /* TnyFolder *folder; */
2536 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2537 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2540 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2542 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2544 /* Remove already purged messages from mime parts list */
2546 while (node != NULL) {
2547 TnyMimePart *part = TNY_MIME_PART (node->data);
2548 if (tny_mime_part_is_purged (part)) {
2549 GList *deleted_node = node;
2550 node = g_list_next (node);
2551 g_object_unref (part);
2552 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2554 node = g_list_next (node);
2558 if (mime_parts == NULL)
2561 n_attachments = g_list_length (mime_parts);
2562 if (n_attachments == 1) {
2563 const gchar *filename;
2565 if (TNY_IS_MSG (mime_parts->data)) {
2567 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2568 filename = tny_header_get_subject (header);
2569 g_object_unref (header);
2570 if (filename == NULL)
2571 filename = _("mail_va_no_subject");
2573 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2575 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2577 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2578 "mcen_nc_purge_files_text",
2579 n_attachments), n_attachments);
2581 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2582 confirmation_message);
2583 g_free (confirmation_message);
2585 if (response != GTK_RESPONSE_OK)
2588 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2589 /* folder = tny_msg_get_folder (msg); */
2590 /* tny_msg_uncache_attachments (msg); */
2591 /* tny_folder_refresh (folder, NULL); */
2592 /* g_object_unref (folder); */
2594 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2595 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2596 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2599 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2600 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2601 tny_msg_rewrite_cache (msg);
2602 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2604 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2605 g_list_free (mime_parts);
2607 if (priv->purge_timeout > 0) {
2608 g_source_remove (priv->purge_timeout);
2609 priv->purge_timeout = 0;
2612 if (priv->remove_attachment_banner) {
2613 gtk_widget_destroy (priv->remove_attachment_banner);
2614 g_object_unref (priv->remove_attachment_banner);
2615 priv->remove_attachment_banner = NULL;
2623 update_window_title (ModestMsgViewWindow *window)
2625 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2627 TnyHeader *header = NULL;
2628 const gchar *subject = NULL;
2630 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2633 header = tny_msg_get_header (msg);
2634 subject = tny_header_get_subject (header);
2635 g_object_unref (msg);
2638 if ((subject == NULL)||(subject[0] == '\0'))
2639 subject = _("mail_va_no_subject");
2641 gtk_window_set_title (GTK_WINDOW (window), subject);
2645 static void on_move_focus (ModestMsgViewWindow *window,
2646 GtkDirectionType direction,
2649 GtkWidget *current_focus = NULL;
2651 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2652 if ((current_focus != NULL) &&
2653 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2654 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");