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,
146 static void set_toolbar_mode (ModestMsgViewWindow *self,
147 ModestToolBarModes mode);
149 static void update_window_title (ModestMsgViewWindow *window);
151 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
154 /* list my signals */
160 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
161 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
162 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
165 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
166 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
167 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
168 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
169 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
170 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
171 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
174 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
175 struct _ModestMsgViewWindowPrivate {
178 GtkWidget *main_scroll;
179 GtkWidget *find_toolbar;
182 /* Progress observers */
183 GtkWidget *progress_bar;
184 GSList *progress_widgets;
187 GtkWidget *progress_toolitem;
188 GtkWidget *cancel_toolitem;
189 GtkWidget *prev_toolitem;
190 GtkWidget *next_toolitem;
191 ModestToolBarModes current_toolbar_mode;
193 /* Optimized view enabled */
194 gboolean optimized_view;
196 /* Whether this was created via the *_new_for_search_result() function. */
197 gboolean is_search_result;
199 /* A reference to the @model of the header view
200 * to allow selecting previous/next messages,
201 * if the message is currently selected in the header view.
203 const gchar *header_folder_id;
204 GtkTreeModel *header_model;
205 GtkTreeRowReference *row_reference;
206 GtkTreeRowReference *next_row_reference;
208 gulong clipboard_change_handler;
209 gulong queue_change_handler;
210 gulong account_removed_handler;
211 gulong row_changed_handler;
212 gulong row_deleted_handler;
213 gulong row_inserted_handler;
214 gulong rows_reordered_handler;
217 GtkWidget *remove_attachment_banner;
219 guint progress_bar_timeout;
224 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
225 MODEST_TYPE_MSG_VIEW_WINDOW, \
226 ModestMsgViewWindowPrivate))
228 static GtkWindowClass *parent_class = NULL;
230 /* uncomment the following if you have defined any signals */
231 static guint signals[LAST_SIGNAL] = {0};
234 modest_msg_view_window_get_type (void)
236 static GType my_type = 0;
238 static const GTypeInfo my_info = {
239 sizeof(ModestMsgViewWindowClass),
240 NULL, /* base init */
241 NULL, /* base finalize */
242 (GClassInitFunc) modest_msg_view_window_class_init,
243 NULL, /* class finalize */
244 NULL, /* class data */
245 sizeof(ModestMsgViewWindow),
247 (GInstanceInitFunc) modest_msg_view_window_init,
250 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
251 "ModestMsgViewWindow",
254 static const GInterfaceInfo modest_header_view_observer_info =
256 (GInterfaceInitFunc) modest_header_view_observer_init,
257 NULL, /* interface_finalize */
258 NULL /* interface_data */
261 g_type_add_interface_static (my_type,
262 MODEST_TYPE_HEADER_VIEW_OBSERVER,
263 &modest_header_view_observer_info);
269 save_state (ModestWindow *self)
271 modest_widget_memory_save (modest_runtime_get_conf (),
273 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
278 restore_settings (ModestMsgViewWindow *self)
280 modest_widget_memory_restore (modest_runtime_get_conf (),
282 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
286 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
288 GObjectClass *gobject_class;
289 ModestWindowClass *modest_window_class;
290 gobject_class = (GObjectClass*) klass;
291 modest_window_class = (ModestWindowClass *) klass;
293 parent_class = g_type_class_peek_parent (klass);
294 gobject_class->finalize = modest_msg_view_window_finalize;
296 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
297 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
298 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
299 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
300 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
301 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
303 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
305 modest_window_class->save_state_func = save_state;
307 signals[MSG_CHANGED_SIGNAL] =
308 g_signal_new ("msg-changed",
309 G_TYPE_FROM_CLASS (gobject_class),
311 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
313 modest_marshal_VOID__POINTER_POINTER,
314 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
317 static void modest_header_view_observer_init(
318 ModestHeaderViewObserverIface *iface_class)
320 iface_class->update_func = modest_msg_view_window_update_model_replaced;
324 modest_msg_view_window_init (ModestMsgViewWindow *obj)
326 ModestMsgViewWindowPrivate *priv;
327 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
329 priv->is_search_result = FALSE;
331 priv->msg_view = NULL;
332 priv->header_model = NULL;
333 priv->header_folder_id = NULL;
334 priv->clipboard_change_handler = 0;
335 priv->queue_change_handler = 0;
336 priv->account_removed_handler = 0;
337 priv->row_changed_handler = 0;
338 priv->row_deleted_handler = 0;
339 priv->row_inserted_handler = 0;
340 priv->rows_reordered_handler = 0;
341 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
343 priv->optimized_view = FALSE;
344 priv->progress_bar_timeout = 0;
345 priv->purge_timeout = 0;
346 priv->remove_attachment_banner = NULL;
347 priv->msg_uid = NULL;
349 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
350 GTK_WINDOW(obj),"applications_email_viewer");
355 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
357 ModestMsgViewWindowPrivate *priv = NULL;
359 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
361 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
363 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
365 if (priv->progress_bar_timeout > 0) {
366 g_source_remove (priv->progress_bar_timeout);
367 priv->progress_bar_timeout = 0;
374 set_toolbar_mode (ModestMsgViewWindow *self,
375 ModestToolBarModes mode)
377 ModestWindowPrivate *parent_priv;
378 ModestMsgViewWindowPrivate *priv;
379 /* GtkWidget *widget = NULL; */
381 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
383 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
384 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
386 /* Sets current toolbar mode */
387 priv->current_toolbar_mode = mode;
389 /* Update toolbar dimming state */
390 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
393 case TOOLBAR_MODE_NORMAL:
394 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
395 /* gtk_action_set_sensitive (widget, TRUE); */
396 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
397 /* gtk_action_set_sensitive (widget, TRUE); */
398 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
399 /* gtk_action_set_sensitive (widget, TRUE); */
400 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
401 /* gtk_action_set_sensitive (widget, TRUE); */
403 if (priv->prev_toolitem)
404 gtk_widget_show (priv->prev_toolitem);
406 if (priv->next_toolitem)
407 gtk_widget_show (priv->next_toolitem);
409 if (priv->progress_toolitem)
410 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
411 if (priv->progress_bar)
412 gtk_widget_hide (priv->progress_bar);
414 if (priv->cancel_toolitem)
415 gtk_widget_hide (priv->cancel_toolitem);
417 /* Hide toolbar if optimized view is enabled */
418 if (priv->optimized_view) {
419 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
420 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
424 case TOOLBAR_MODE_TRANSFER:
425 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
426 /* gtk_action_set_sensitive (widget, FALSE); */
427 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
428 /* gtk_action_set_sensitive (widget, FALSE); */
429 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
430 /* gtk_action_set_sensitive (widget, FALSE); */
431 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
432 /* gtk_action_set_sensitive (widget, FALSE); */
434 if (priv->prev_toolitem)
435 gtk_widget_hide (priv->prev_toolitem);
437 if (priv->next_toolitem)
438 gtk_widget_hide (priv->next_toolitem);
440 if (priv->progress_toolitem)
441 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
442 if (priv->progress_bar)
443 gtk_widget_show (priv->progress_bar);
445 if (priv->cancel_toolitem)
446 gtk_widget_show (priv->cancel_toolitem);
448 /* Show toolbar if it's hiden (optimized view ) */
449 if (priv->optimized_view) {
450 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
451 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
456 g_return_if_reached ();
463 menubar_to_menu (GtkUIManager *ui_manager)
465 GtkWidget *main_menu;
467 GList *iter, *children;
469 /* Create new main menu */
470 main_menu = gtk_menu_new();
472 /* Get the menubar from the UI manager */
473 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
475 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
479 menu = GTK_WIDGET (iter->data);
480 gtk_widget_reparent(menu, main_menu);
482 iter = g_list_next (iter);
484 g_list_free (children);
490 init_window (ModestMsgViewWindow *obj)
492 GtkWidget *main_vbox;
493 ModestMsgViewWindowPrivate *priv;
494 ModestWindowPrivate *parent_priv;
496 GtkAction *action = NULL;
498 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
499 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
501 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
502 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
503 main_vbox = gtk_vbox_new (FALSE, 6);
506 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
507 conf = modest_runtime_get_conf ();
508 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
509 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
510 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
511 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
512 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
513 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
514 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
515 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
516 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
517 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
519 #ifdef MODEST_USE_MOZEMBED
520 priv->main_scroll = priv->msg_view;
521 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
523 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
524 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
526 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
527 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
528 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
530 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
531 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
533 priv->find_toolbar = hildon_find_toolbar_new (NULL);
534 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
535 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
536 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
537 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
539 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);
540 gtk_widget_show_all (GTK_WIDGET(main_vbox));
544 modest_msg_view_window_disconnect_signals (ModestWindow *self)
546 ModestMsgViewWindowPrivate *priv;
547 ModestHeaderView *header_view = NULL;
548 ModestWindow *main_window = NULL;
550 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
552 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
553 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
554 priv->clipboard_change_handler))
555 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
556 priv->clipboard_change_handler);
558 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
559 priv->queue_change_handler))
560 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
561 priv->queue_change_handler);
563 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
564 priv->account_removed_handler))
565 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
566 priv->account_removed_handler);
568 if (priv->header_model) {
569 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
570 priv->row_changed_handler))
571 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
572 priv->row_changed_handler);
574 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
575 priv->row_deleted_handler))
576 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
577 priv->row_deleted_handler);
579 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
580 priv->row_inserted_handler))
581 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
582 priv->row_inserted_handler);
584 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
585 priv->rows_reordered_handler))
586 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
587 priv->rows_reordered_handler);
590 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
591 FALSE); /* don't create */
595 header_view = MODEST_HEADER_VIEW(
596 modest_main_window_get_child_widget(
597 MODEST_MAIN_WINDOW(main_window),
598 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
599 if (header_view == NULL)
602 modest_header_view_remove_observer(header_view,
603 MODEST_HEADER_VIEW_OBSERVER(self));
607 modest_msg_view_window_finalize (GObject *obj)
609 ModestMsgViewWindowPrivate *priv;
611 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
613 /* Sanity check: shouldn't be needed, the window mgr should
614 call this function before */
615 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
617 if (priv->header_model != NULL) {
618 g_object_unref (priv->header_model);
619 priv->header_model = NULL;
622 if (priv->progress_bar_timeout > 0) {
623 g_source_remove (priv->progress_bar_timeout);
624 priv->progress_bar_timeout = 0;
627 if (priv->remove_attachment_banner) {
628 gtk_widget_destroy (priv->remove_attachment_banner);
629 g_object_unref (priv->remove_attachment_banner);
630 priv->remove_attachment_banner = NULL;
633 if (priv->purge_timeout > 0) {
634 g_source_remove (priv->purge_timeout);
635 priv->purge_timeout = 0;
638 if (priv->row_reference) {
639 gtk_tree_row_reference_free (priv->row_reference);
640 priv->row_reference = NULL;
643 if (priv->next_row_reference) {
644 gtk_tree_row_reference_free (priv->next_row_reference);
645 priv->next_row_reference = NULL;
649 g_free (priv->msg_uid);
650 priv->msg_uid = NULL;
653 G_OBJECT_CLASS(parent_class)->finalize (obj);
657 select_next_valid_row (GtkTreeModel *model,
658 GtkTreeRowReference **row_reference,
661 GtkTreeIter tmp_iter;
662 GtkTreePath *path, *next;
663 gboolean retval = FALSE;
665 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
667 path = gtk_tree_row_reference_get_path (*row_reference);
668 gtk_tree_model_get_iter (model, &tmp_iter, path);
669 gtk_tree_row_reference_free (*row_reference);
670 *row_reference = NULL;
672 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
673 next = gtk_tree_model_get_path (model, &tmp_iter);
674 *row_reference = gtk_tree_row_reference_new (model, next);
676 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
677 next = gtk_tree_model_get_path (model, &tmp_iter);
679 /* Ensure that we are not selecting the same */
680 if (gtk_tree_path_compare (path, next) != 0) {
681 *row_reference = gtk_tree_row_reference_new (model, next);
687 gtk_tree_path_free (path);
692 /* TODO: This should be in _init(), with the parameters as properties. */
694 modest_msg_view_window_construct (ModestMsgViewWindow *self,
695 const gchar *modest_account_name,
696 const gchar *msg_uid)
699 ModestMsgViewWindowPrivate *priv = NULL;
700 ModestWindowPrivate *parent_priv = NULL;
701 ModestDimmingRulesGroup *menu_rules_group = NULL;
702 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
703 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
704 GtkActionGroup *action_group = NULL;
705 GError *error = NULL;
706 GdkPixbuf *window_icon;
708 obj = G_OBJECT (self);
709 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
710 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
712 priv->msg_uid = g_strdup (msg_uid);
714 parent_priv->ui_manager = gtk_ui_manager_new();
715 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
717 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
718 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
720 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
721 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
722 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
724 /* Add common actions */
725 gtk_action_group_add_actions (action_group,
726 modest_action_entries,
727 G_N_ELEMENTS (modest_action_entries),
729 gtk_action_group_add_toggle_actions (action_group,
730 modest_toggle_action_entries,
731 G_N_ELEMENTS (modest_toggle_action_entries),
733 gtk_action_group_add_toggle_actions (action_group,
734 msg_view_toggle_action_entries,
735 G_N_ELEMENTS (msg_view_toggle_action_entries),
737 gtk_action_group_add_radio_actions (action_group,
738 msg_view_zoom_action_entries,
739 G_N_ELEMENTS (msg_view_zoom_action_entries),
741 G_CALLBACK (modest_ui_actions_on_change_zoom),
744 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
745 g_object_unref (action_group);
747 /* Load the UI definition */
748 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
751 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
752 g_error_free (error);
757 /* Add common dimming rules */
758 modest_dimming_rules_group_add_rules (menu_rules_group,
759 modest_msg_view_menu_dimming_entries,
760 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
761 MODEST_WINDOW (self));
762 modest_dimming_rules_group_add_rules (toolbar_rules_group,
763 modest_msg_view_toolbar_dimming_entries,
764 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
765 MODEST_WINDOW (self));
766 modest_dimming_rules_group_add_rules (clipboard_rules_group,
767 modest_msg_view_clipboard_dimming_entries,
768 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
769 MODEST_WINDOW (self));
771 /* Insert dimming rules group for this window */
772 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
773 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
774 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
775 g_object_unref (menu_rules_group);
776 g_object_unref (toolbar_rules_group);
777 g_object_unref (clipboard_rules_group);
779 /* Add accelerators */
780 gtk_window_add_accel_group (GTK_WINDOW (obj),
781 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
784 init_window (MODEST_MSG_VIEW_WINDOW(obj));
785 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
787 /* Set window icon */
788 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
790 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
791 g_object_unref (window_icon);
794 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
796 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
797 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
798 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
799 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
800 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
801 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
802 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
803 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
804 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
805 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
807 g_signal_connect (G_OBJECT (obj), "key-release-event",
808 G_CALLBACK (modest_msg_view_window_key_release_event),
811 g_signal_connect (G_OBJECT (obj), "window-state-event",
812 G_CALLBACK (modest_msg_view_window_window_state_event),
815 g_signal_connect (G_OBJECT (obj), "move-focus",
816 G_CALLBACK (on_move_focus), obj);
818 /* Mail Operation Queue */
819 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
821 G_CALLBACK (on_queue_changed),
824 /* Account manager */
825 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
827 G_CALLBACK(on_account_removed),
830 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
832 priv->last_search = NULL;
834 /* Init the clipboard actions dim status */
835 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
837 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
839 /* Check toolbar dimming rules */
840 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
841 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
845 /* FIXME: parameter checks */
847 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
848 const gchar *modest_account_name,
849 const gchar *msg_uid,
851 GtkTreeRowReference *row_reference)
853 ModestMsgViewWindow *window = NULL;
854 ModestMsgViewWindowPrivate *priv = NULL;
855 TnyFolder *header_folder = NULL;
856 ModestHeaderView *header_view = NULL;
857 ModestWindow *main_window = NULL;
859 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
860 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
862 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
864 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
866 /* Remember the message list's TreeModel so we can detect changes
867 * and change the list selection when necessary: */
869 main_window = modest_window_mgr_get_main_window(
870 modest_runtime_get_window_mgr(), FALSE); /* don't create */
872 g_warning ("%s: BUG: no main window", __FUNCTION__);
876 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
877 MODEST_MAIN_WINDOW(main_window),
878 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
879 if (header_view != NULL){
880 header_folder = modest_header_view_get_folder(header_view);
881 g_assert(header_folder != NULL);
882 priv->header_folder_id = tny_folder_get_id(header_folder);
883 g_assert(priv->header_folder_id != NULL);
884 g_object_unref(header_folder);
887 priv->header_model = g_object_ref(model);
888 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
889 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
890 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
892 priv->row_changed_handler = g_signal_connect(
893 GTK_TREE_MODEL(model), "row-changed",
894 G_CALLBACK(modest_msg_view_window_on_row_changed),
896 priv->row_deleted_handler = g_signal_connect(
897 GTK_TREE_MODEL(model), "row-deleted",
898 G_CALLBACK(modest_msg_view_window_on_row_deleted),
900 priv->row_inserted_handler = g_signal_connect (
901 GTK_TREE_MODEL(model), "row-inserted",
902 G_CALLBACK(modest_msg_view_window_on_row_inserted),
904 priv->rows_reordered_handler = g_signal_connect(
905 GTK_TREE_MODEL(model), "rows-reordered",
906 G_CALLBACK(modest_msg_view_window_on_row_reordered),
909 if (header_view != NULL){
910 modest_header_view_add_observer(header_view,
911 MODEST_HEADER_VIEW_OBSERVER(window));
914 gtk_widget_show_all (GTK_WIDGET (window));
916 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
917 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
919 modest_msg_view_window_update_priority (window);
921 /* Check toolbar dimming rules */
922 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
924 return MODEST_WINDOW(window);
928 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
929 const gchar *modest_account_name,
930 const gchar *msg_uid)
932 ModestMsgViewWindow *window = NULL;
933 ModestMsgViewWindowPrivate *priv = NULL;
935 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
936 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
937 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
939 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
941 /* Remember that this is a search result,
942 * so we can disable some UI appropriately: */
943 priv->is_search_result = TRUE;
945 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
947 return MODEST_WINDOW(window);
951 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
952 const gchar *modest_account_name,
953 const gchar *msg_uid)
956 ModestMsgViewWindowPrivate *priv;
957 g_return_val_if_fail (msg, NULL);
959 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
960 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
961 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
962 modest_account_name, msg_uid);
964 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
966 return MODEST_WINDOW(obj);
969 void modest_msg_view_window_on_row_changed(
970 GtkTreeModel *header_model,
973 ModestMsgViewWindow *window){
974 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
977 void modest_msg_view_window_on_row_deleted(
978 GtkTreeModel *header_model,
980 ModestMsgViewWindow *window){
981 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
984 /* On insertions we check if the folder still has the message we are
985 * showing or do not. If do not, we do nothing. Which means we are still
986 * not attached to any header folder and thus next/prev buttons are
987 * still dimmed. Once the message that is shown by msg-view is found, the
988 * new model of header-view will be attached and the references will be set.
989 * On each further insertions dimming rules will be checked. However
990 * this requires extra CPU time at least works.
991 * (An message might be deleted from TnyFolder and thus will not be
992 * inserted into the model again for example if it is removed by the
993 * imap server and the header view is refreshed.)
995 void modest_msg_view_window_on_row_inserted(
996 GtkTreeModel *new_model,
997 GtkTreePath *tree_path,
998 GtkTreeIter *tree_iter,
999 ModestMsgViewWindow *window){
1000 ModestMsgViewWindowPrivate *priv = NULL;
1001 TnyHeader *header = NULL;
1004 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1006 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1008 /* If we already has a model attached then the message shown by
1009 * msg-view is in it, and thus we do not need any actions but
1010 * to check the dimming rules.*/
1011 if(priv->header_model != NULL){
1012 gtk_tree_row_reference_free(priv->next_row_reference);
1013 priv->next_row_reference = gtk_tree_row_reference_copy(
1014 priv->row_reference);
1015 select_next_valid_row (priv->header_model,
1016 &(priv->next_row_reference), FALSE);
1017 modest_ui_actions_check_toolbar_dimming_rules (
1018 MODEST_WINDOW (window));
1022 /* Check if the newly inserted message is the same we are actually
1023 * showing. IF not, we should remain detached from the header model
1024 * and thus prev and next toolbarbuttons should remain dimmed. */
1025 gtk_tree_model_get (new_model, tree_iter,
1026 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1027 uid = modest_tny_folder_get_header_unique_id(header);
1028 if(!g_str_equal(priv->msg_uid, uid)){
1034 /* Setup row_reference for the actual msg. */
1035 priv->row_reference = gtk_tree_row_reference_new(
1036 new_model, tree_path);
1037 if(priv->row_reference == NULL){
1038 g_warning("No reference for msg header item.");
1042 /* Attach new_model and connect some callback to it to become able
1043 * to detect changes in header-view. */
1044 priv->header_model = g_object_ref(new_model);
1045 g_signal_connect (new_model, "row-changed",
1046 G_CALLBACK (modest_msg_view_window_on_row_changed),
1048 g_signal_connect (new_model, "row-deleted",
1049 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1051 g_signal_connect (new_model, "rows-reordered",
1052 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1055 /* Now set up next_row_reference. */
1056 priv->next_row_reference = gtk_tree_row_reference_copy(
1057 priv->row_reference);
1058 select_next_valid_row (priv->header_model,
1059 &(priv->next_row_reference), FALSE);
1061 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1064 void modest_msg_view_window_on_row_reordered(
1065 GtkTreeModel *header_model,
1069 ModestMsgViewWindow *window){
1070 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1073 /* The modest_msg_view_window_update_model_replaced implements update
1074 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1075 * actually belongs to the header-view is the same as the TnyFolder of
1076 * the message of msg-view or not. If they are different, there is
1077 * nothing to do. If they are the same, then the model has replaced and
1078 * the reference in msg-view shall be replaced from the old model to
1079 * the new model. In this case the view will be detached from it's
1080 * header folder. From this point the next/prev buttons are dimmed.
1082 void modest_msg_view_window_update_model_replaced(
1083 ModestHeaderViewObserver *observer,
1084 GtkTreeModel *model,
1085 const gchar *tny_folder_id){
1086 ModestMsgViewWindowPrivate *priv = NULL;
1087 ModestMsgViewWindow *window = NULL;
1089 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1090 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1092 window = MODEST_MSG_VIEW_WINDOW(observer);
1093 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1095 /* If there is an other folder in the header-view then we do
1096 * not care about it's model (msg list). Else if the
1097 * header-view shows the folder the msg shown by us is in, we
1098 * shall replace our model reference and make some check. */
1099 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1102 /* Model is changed(replaced), so we should forget the old
1103 * one. Because there might be other references and there
1104 * might be some change on the model even if we unreferenced
1105 * it, we need to disconnect our signals here. */
1106 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1107 priv->row_changed_handler))
1108 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1109 priv->row_changed_handler);
1110 priv->row_changed_handler = 0;
1111 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1112 priv->row_deleted_handler))
1113 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1114 priv->row_deleted_handler);
1115 priv->row_deleted_handler = 0;
1116 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1117 priv->row_inserted_handler))
1118 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1119 priv->row_inserted_handler);
1120 priv->row_inserted_handler = 0;
1121 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1122 priv->rows_reordered_handler))
1123 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1124 priv->rows_reordered_handler);
1125 priv->rows_reordered_handler = 0;
1126 g_object_unref(priv->header_model);
1127 priv->header_model = NULL;
1128 g_object_unref(priv->row_reference);
1129 priv->row_reference = NULL;
1130 g_object_unref(priv->next_row_reference);
1131 priv->next_row_reference = NULL;
1133 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1135 g_assert(model != NULL);
1137 /* Also we must connect to the new model for row insertions.
1138 * Only for insertions now. We will need other ones only after
1139 * the msg is show by msg-view is added to the new model. */
1140 priv->row_inserted_handler = g_signal_connect (
1141 model, "row-inserted",
1142 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1147 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1149 ModestMsgViewWindowPrivate *priv= NULL;
1151 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1152 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1154 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1158 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1160 ModestMsgViewWindowPrivate *priv= NULL;
1162 TnyHeader *header = NULL;
1163 GtkTreePath *path = NULL;
1166 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1167 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1169 /* If the message was not obtained from a treemodel,
1170 * for instance if it was opened directly by the search UI:
1172 if (priv->header_model == NULL) {
1173 msg = modest_msg_view_window_get_message (self);
1175 header = tny_msg_get_header (msg);
1176 g_object_unref (msg);
1181 /* Get iter of the currently selected message in the header view: */
1182 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1183 * instead of sometimes retrieving it from the header view?
1184 * Then we wouldn't be dependent on the message actually still being selected
1185 * in the header view. murrayc. */
1186 if (!gtk_tree_row_reference_valid (priv->row_reference))
1188 path = gtk_tree_row_reference_get_path (priv->row_reference);
1189 g_return_val_if_fail (path != NULL, NULL);
1190 gtk_tree_model_get_iter (priv->header_model,
1194 /* Get current message header */
1195 gtk_tree_model_get (priv->header_model, &iter,
1196 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1199 gtk_tree_path_free (path);
1204 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1206 ModestMsgViewWindowPrivate *priv;
1208 g_return_val_if_fail (self, NULL);
1210 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1212 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1216 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1218 ModestMsgViewWindowPrivate *priv;
1220 g_return_val_if_fail (self, NULL);
1222 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1224 return (const gchar*) priv->msg_uid;
1228 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1231 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1232 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1233 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1237 is_active = gtk_toggle_action_get_active (toggle);
1240 gtk_widget_show (priv->find_toolbar);
1241 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1243 gtk_widget_hide (priv->find_toolbar);
1246 /* update the toggle buttons status */
1247 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1248 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1249 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1250 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1255 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1256 ModestMsgViewWindow *obj)
1258 GtkToggleAction *toggle;
1259 ModestWindowPrivate *parent_priv;
1260 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1262 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1263 gtk_toggle_action_set_active (toggle, FALSE);
1267 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1268 ModestMsgViewWindow *obj)
1270 gchar *current_search;
1271 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1273 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1274 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1278 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1280 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1281 g_free (current_search);
1282 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1286 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1288 g_free (priv->last_search);
1289 priv->last_search = g_strdup (current_search);
1290 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1293 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1294 g_free (priv->last_search);
1295 priv->last_search = NULL;
1297 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1300 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1301 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1302 g_free (priv->last_search);
1303 priv->last_search = NULL;
1305 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1309 g_free (current_search);
1314 modest_msg_view_window_set_zoom (ModestWindow *window,
1317 ModestMsgViewWindowPrivate *priv;
1318 ModestWindowPrivate *parent_priv;
1319 GtkAction *action = NULL;
1320 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1322 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1324 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1325 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1326 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1328 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1329 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1331 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1335 modest_msg_view_window_get_zoom (ModestWindow *window)
1337 ModestMsgViewWindowPrivate *priv;
1339 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1341 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1342 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1346 modest_msg_view_window_zoom_plus (ModestWindow *window)
1348 ModestWindowPrivate *parent_priv;
1349 GtkRadioAction *zoom_radio_action;
1350 GSList *group, *node;
1352 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1353 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1354 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1356 group = gtk_radio_action_get_group (zoom_radio_action);
1358 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1359 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1363 for (node = group; node != NULL; node = g_slist_next (node)) {
1364 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1365 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1373 modest_msg_view_window_zoom_minus (ModestWindow *window)
1375 ModestWindowPrivate *parent_priv;
1376 GtkRadioAction *zoom_radio_action;
1377 GSList *group, *node;
1379 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1380 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1381 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1383 group = gtk_radio_action_get_group (zoom_radio_action);
1385 for (node = group; node != NULL; node = g_slist_next (node)) {
1386 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1387 if (node->next != NULL) {
1388 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1391 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1401 modest_msg_view_window_key_release_event (GtkWidget *window,
1405 if (event->type == GDK_KEY_RELEASE) {
1406 switch (event->keyval) {
1408 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1412 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1425 modest_msg_view_window_scroll_up (ModestWindow *window)
1427 ModestMsgViewWindowPrivate *priv;
1428 gboolean return_value;
1430 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1431 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1435 modest_msg_view_window_scroll_down (ModestWindow *window)
1437 ModestMsgViewWindowPrivate *priv;
1438 gboolean return_value;
1440 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1441 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1445 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1448 ModestMsgViewWindowPrivate *priv;
1449 GtkTreeIter tmp_iter;
1450 gboolean is_last_selected;
1452 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1453 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1455 /*if no model (so no rows at all), then virtually we are the last*/
1456 if (!priv->header_model)
1459 path = gtk_tree_row_reference_get_path (priv->row_reference);
1463 is_last_selected = TRUE;
1464 while (is_last_selected) {
1466 gtk_tree_path_next (path);
1467 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1469 gtk_tree_model_get (priv->header_model, &tmp_iter,
1470 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1472 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1473 is_last_selected = FALSE;
1475 gtk_tree_path_free (path);
1476 return is_last_selected;
1480 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1482 ModestMsgViewWindowPrivate *priv;
1484 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1485 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1487 return priv->header_model != NULL;
1491 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1493 ModestMsgViewWindowPrivate *priv;
1495 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1496 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1498 return priv->is_search_result;
1502 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1505 ModestMsgViewWindowPrivate *priv;
1506 gboolean is_first_selected;
1507 GtkTreeIter tmp_iter;
1508 /* gchar * path_string;*/
1510 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1511 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1513 /*if no model (so no rows at all), then virtually we are the first*/
1514 if (!priv->header_model)
1517 path = gtk_tree_row_reference_get_path (priv->row_reference);
1521 /* path_string = gtk_tree_path_to_string (path);
1522 is_first_selected = strcmp (path_string, "0");
1524 g_free (path_string);
1525 gtk_tree_path_free (path);
1527 return is_first_selected;*/
1529 is_first_selected = TRUE;
1530 while (is_first_selected) {
1532 if(!gtk_tree_path_prev (path))
1534 /* Here the 'if' is needless for logic, but let make sure
1535 * iter is valid for gtk_tree_model_get. */
1536 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1538 gtk_tree_model_get (priv->header_model, &tmp_iter,
1539 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1541 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1542 is_first_selected = FALSE;
1544 gtk_tree_path_free (path);
1545 return is_first_selected;
1549 * Reads the message whose summary item is @header. It takes care of
1550 * several things, among others:
1552 * If the message was not previously downloaded then ask the user
1553 * before downloading. If there is no connection launch the connection
1554 * dialog. Update toolbar dimming rules.
1556 * Returns: TRUE if the mail operation was started, otherwise if the
1557 * user do not want to download the message, or if the user do not
1558 * want to connect, then the operation is not issued
1561 message_reader (ModestMsgViewWindow *window,
1562 ModestMsgViewWindowPrivate *priv,
1564 GtkTreeRowReference *row_reference)
1566 ModestMailOperation *mail_op = NULL;
1567 ModestMailOperationTypeOperation op_type;
1568 gboolean already_showing = FALSE;
1569 ModestWindow *msg_window = NULL;
1570 ModestWindowMgr *mgr;
1572 g_return_val_if_fail (row_reference != NULL, FALSE);
1574 mgr = modest_runtime_get_window_mgr ();
1575 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1576 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1579 gtk_window_present (GTK_WINDOW (msg_window));
1580 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1584 /* Msg download completed */
1585 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1586 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1588 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1590 /* Ask the user if he wants to download the message if
1592 if (!tny_device_is_online (modest_runtime_get_device())) {
1593 TnyFolder *folder = NULL;
1594 GtkResponseType response;
1596 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1597 _("mcen_nc_get_msg"));
1598 if (response == GTK_RESPONSE_CANCEL)
1601 /* Offer the connection dialog if necessary */
1602 folder = tny_header_get_folder (header);
1604 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1605 TNY_FOLDER_STORE (folder))) {
1606 g_object_unref (folder);
1609 g_object_unref (folder);
1614 /* New mail operation */
1615 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1616 modest_ui_actions_get_msgs_full_error_handler,
1619 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1620 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1621 g_object_unref (mail_op);
1623 /* Update toolbar dimming rules */
1624 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1630 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1632 ModestMsgViewWindowPrivate *priv;
1633 GtkTreePath *path= NULL;
1634 GtkTreeIter tmp_iter;
1636 gboolean retval = TRUE;
1637 GtkTreeRowReference *row_reference = NULL;
1639 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1640 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1642 /* Update the next row reference if it's not valid. This could
1643 happen if for example the header which it was pointing to,
1644 was deleted. The best place to do it is in the row-deleted
1645 handler but the tinymail model do not work like the glib
1646 tree models and reports the deletion when the row is still
1648 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1649 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1650 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1651 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1654 if (priv->next_row_reference)
1655 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1659 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1661 gtk_tree_model_get_iter (priv->header_model,
1664 gtk_tree_path_free (path);
1666 gtk_tree_model_get (priv->header_model, &tmp_iter,
1667 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1670 /* Read the message & show it */
1671 if (!message_reader (window, priv, header, row_reference)) {
1673 gtk_tree_row_reference_free (row_reference);
1677 g_object_unref (header);
1683 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1685 ModestMsgViewWindowPrivate *priv = NULL;
1686 TnyHeader *header = NULL;
1688 GtkTreePath *path = NULL;
1689 GtkTreeRowReference *row_reference = NULL;
1691 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1692 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1694 /* Check that the model is not empty */
1695 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1698 /* Get the header */
1699 gtk_tree_model_get (priv->header_model,
1701 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1703 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1704 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1705 g_object_unref (header);
1706 return modest_msg_view_window_select_next_message (self);
1709 path = gtk_tree_model_get_path (priv->header_model, &iter);
1710 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1711 gtk_tree_path_free (path);
1713 /* Read the message & show it */
1714 message_reader (self, priv, header, row_reference);
1717 g_object_unref (header);
1723 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1725 ModestMsgViewWindowPrivate *priv = NULL;
1727 GtkTreeRowReference *row_reference = NULL;
1729 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1730 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1732 /* Return inmediatly if there is no header model */
1733 if (!priv->header_model)
1736 path = gtk_tree_row_reference_get_path (priv->row_reference);
1737 while (gtk_tree_path_prev (path)) {
1741 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1742 gtk_tree_model_get (priv->header_model, &iter,
1743 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1747 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1748 g_object_unref (header);
1752 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1753 /* Read the message & show it */
1754 if (!message_reader (window, priv, header, row_reference)) {
1755 gtk_tree_row_reference_free (row_reference);
1756 g_object_unref (header);
1760 gtk_tree_path_free (path);
1761 g_object_unref (header);
1766 gtk_tree_path_free (path);
1771 view_msg_cb (ModestMailOperation *mail_op,
1776 ModestMsgViewWindow *self = NULL;
1777 ModestMsgViewWindowPrivate *priv = NULL;
1778 GtkTreeRowReference *row_reference = NULL;
1780 /* If there was any error */
1781 row_reference = (GtkTreeRowReference *) user_data;
1782 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1783 gtk_tree_row_reference_free (row_reference);
1787 /* Get the window */
1788 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1789 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1790 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1792 /* Update the row reference */
1793 gtk_tree_row_reference_free (priv->row_reference);
1794 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1795 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1796 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1797 gtk_tree_row_reference_free (row_reference);
1799 /* Mark header as read */
1800 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1801 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1803 /* Set new message */
1804 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1805 modest_msg_view_window_update_priority (self);
1806 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1807 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1809 /* Set the new message uid of the window */
1810 if (priv->msg_uid) {
1811 g_free (priv->msg_uid);
1812 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1815 /* Notify the observers */
1816 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1817 0, priv->header_model, priv->row_reference);
1819 /* Free new references */
1820 g_object_unref (self);
1824 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1826 ModestMsgViewWindowPrivate *priv;
1828 TnyFolderType folder_type;
1830 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1832 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1834 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1838 folder = tny_msg_get_folder (msg);
1840 folder_type = tny_folder_get_folder_type (folder);
1841 g_object_unref (folder);
1843 g_object_unref (msg);
1851 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1853 ModestMsgViewWindowPrivate *priv;
1854 TnyHeaderFlags flags = 0;
1856 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1858 if (priv->header_model) {
1861 GtkTreePath *path = NULL;
1863 path = gtk_tree_row_reference_get_path (priv->row_reference);
1864 g_return_if_fail (path != NULL);
1865 gtk_tree_model_get_iter (priv->header_model,
1867 gtk_tree_row_reference_get_path (priv->row_reference));
1869 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1871 flags = tny_header_get_flags (header);
1872 gtk_tree_path_free (path);
1875 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1880 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1882 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1883 ModestWindowPrivate *parent_priv;
1884 ModestWindowMgr *mgr;
1885 gboolean is_fullscreen;
1886 GtkAction *fs_toggle_action;
1889 mgr = modest_runtime_get_window_mgr ();
1890 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1892 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1894 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1895 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1896 if (is_fullscreen != active) {
1897 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1906 set_homogeneous (GtkWidget *widget,
1909 if (GTK_IS_TOOL_ITEM (widget)) {
1910 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1911 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1916 modest_msg_view_window_show_toolbar (ModestWindow *self,
1917 gboolean show_toolbar)
1919 ModestMsgViewWindowPrivate *priv = NULL;
1920 ModestWindowPrivate *parent_priv;
1921 GtkWidget *reply_button = NULL, *menu = NULL;
1922 GtkWidget *placeholder = NULL;
1924 const gchar *action_name;
1927 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1928 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1930 /* Set optimized view status */
1931 priv->optimized_view = !show_toolbar;
1933 if (!parent_priv->toolbar) {
1934 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1936 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1938 /* Set homogeneous toolbar */
1939 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1940 set_homogeneous, NULL);
1942 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1943 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1944 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1945 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1946 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1947 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1948 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1949 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1951 /* Add ProgressBar (Transfer toolbar) */
1952 priv->progress_bar = modest_progress_bar_widget_new ();
1953 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1954 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1955 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1956 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1957 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1959 /* Connect cancel 'clicked' signal to abort progress mode */
1960 g_signal_connect(priv->cancel_toolitem, "clicked",
1961 G_CALLBACK(cancel_progressbar),
1964 /* Add it to the observers list */
1965 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1968 hildon_window_add_toolbar (HILDON_WINDOW (self),
1969 GTK_TOOLBAR (parent_priv->toolbar));
1972 /* Set reply button tap and hold menu */
1973 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1974 "/ToolBar/ToolbarMessageReply");
1975 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1976 "/ToolbarReplyCSM");
1977 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1981 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1982 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1983 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1985 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1986 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1989 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1990 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1993 /* Update also the actions (to update the toggles in the
1994 menus), we have to do it manually because some other window
1995 of the same time could have changed it (remember that the
1996 toolbar fullscreen mode is shared by all the windows of the
1998 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1999 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2001 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2003 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2004 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2009 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2011 ModestMsgViewWindow *window)
2013 if (!GTK_WIDGET_VISIBLE (window))
2016 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2020 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2022 ModestMsgViewWindowPrivate *priv;
2024 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2025 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2027 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2031 cancel_progressbar (GtkToolButton *toolbutton,
2032 ModestMsgViewWindow *self)
2035 ModestMsgViewWindowPrivate *priv;
2037 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2039 /* Get operation observers and cancel its current operation */
2040 tmp = priv->progress_widgets;
2042 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2043 tmp=g_slist_next(tmp);
2047 observers_empty (ModestMsgViewWindow *self)
2050 ModestMsgViewWindowPrivate *priv;
2051 gboolean is_empty = TRUE;
2052 guint pending_ops = 0;
2054 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2055 tmp = priv->progress_widgets;
2057 /* Check all observers */
2058 while (tmp && is_empty) {
2059 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2060 is_empty = pending_ops == 0;
2062 tmp = g_slist_next(tmp);
2069 on_account_removed (TnyAccountStore *account_store,
2070 TnyAccount *account,
2073 /* Do nothing if it's a transport account, because we only
2074 show the messages of a store account */
2075 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2076 const gchar *parent_acc = NULL;
2077 const gchar *our_acc = NULL;
2079 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2080 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2082 /* Close this window if I'm showing a message of the removed account */
2083 if (strcmp (parent_acc, our_acc) == 0)
2084 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2089 on_queue_changed (ModestMailOperationQueue *queue,
2090 ModestMailOperation *mail_op,
2091 ModestMailOperationQueueNotification type,
2092 ModestMsgViewWindow *self)
2095 ModestMsgViewWindowPrivate *priv;
2096 ModestMailOperationTypeOperation op_type;
2097 ModestToolBarModes mode;
2099 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2100 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2102 /* If this operations was created by another window, do nothing */
2103 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2106 /* Get toolbar mode from operation id*/
2107 op_type = modest_mail_operation_get_type_operation (mail_op);
2109 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2110 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2111 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2112 mode = TOOLBAR_MODE_TRANSFER;
2115 mode = TOOLBAR_MODE_NORMAL;
2119 /* Add operation observers and change toolbar if neccessary*/
2120 tmp = priv->progress_widgets;
2122 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2123 if (mode == TOOLBAR_MODE_TRANSFER) {
2124 /* Enable transfer toolbar mode */
2125 set_toolbar_transfer_mode(self);
2127 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2129 tmp = g_slist_next (tmp);
2134 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2135 if (mode == TOOLBAR_MODE_TRANSFER) {
2137 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2139 tmp = g_slist_next (tmp);
2143 /* If no more operations are being observed, NORMAL mode is enabled again */
2144 if (observers_empty (self)) {
2145 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2153 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2155 ModestMsgViewWindowPrivate *priv;
2156 GList *selected_attachments = NULL;
2158 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2159 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2161 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2163 return selected_attachments;
2167 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2169 ModestMsgViewWindowPrivate *priv;
2170 const gchar *msg_uid;
2171 gchar *attachment_uid = NULL;
2172 gint attachment_index = 0;
2175 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2176 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2177 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2179 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2180 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2181 attachment_index = g_list_index (attachments, mime_part);
2182 g_list_free (attachments);
2184 if (msg_uid && attachment_index >= 0) {
2185 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2188 if (mime_part == NULL) {
2189 gboolean error = FALSE;
2190 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2191 if (selected_attachments == NULL) {
2193 } else if (g_list_length (selected_attachments) > 1) {
2194 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2197 mime_part = (TnyMimePart *) selected_attachments->data;
2198 g_object_ref (mime_part);
2200 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2201 g_list_free (selected_attachments);
2206 g_object_ref (mime_part);
2209 if (tny_mime_part_is_purged (mime_part)) {
2210 g_object_unref (mime_part);
2214 if (!TNY_IS_MSG (mime_part)) {
2215 gchar *filepath = NULL;
2216 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2217 TnyFsStream *temp_stream = NULL;
2218 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2221 const gchar *content_type;
2222 content_type = tny_mime_part_get_content_type (mime_part);
2223 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2225 modest_platform_activate_file (filepath, content_type);
2226 g_object_unref (temp_stream);
2228 /* NOTE: files in the temporary area will be automatically
2229 * cleaned after some time if they are no longer in use */
2232 /* message attachment */
2233 TnyHeader *header = NULL;
2234 ModestWindowMgr *mgr;
2235 ModestWindow *msg_win = NULL;
2238 header = tny_msg_get_header (TNY_MSG (mime_part));
2239 mgr = modest_runtime_get_window_mgr ();
2240 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2243 if (msg_win) /* there is already a window for this uid; top it */
2244 gtk_window_present (GTK_WINDOW(msg_win));
2246 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2247 * thus, we don't do anything */
2248 g_warning ("window for is already being created");
2250 /* it's not found, so create a new window for it */
2251 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2252 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2254 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2255 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2256 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2257 modest_window_get_zoom (MODEST_WINDOW (window)));
2258 modest_window_mgr_register_window (mgr, msg_win);
2259 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2260 gtk_widget_show_all (GTK_WIDGET (msg_win));
2263 g_object_unref (mime_part);
2279 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2280 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2281 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2282 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2285 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2289 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2290 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2291 g_free (pair->filename);
2292 g_object_unref (pair->part);
2293 g_slice_free (SaveMimePartPair, pair);
2295 g_list_free (info->pairs);
2298 gtk_widget_destroy (info->banner);
2299 g_object_unref (info->banner);
2300 g_slice_free (SaveMimePartInfo, info);
2305 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2307 if (info->pairs != NULL) {
2308 save_mime_part_to_file (info);
2311 result = info->result;
2313 /* This is a GDK lock because we are an idle callback and
2314 * hildon_banner_show_information is or does Gtk+ code */
2316 gdk_threads_enter (); /* CHECKED */
2317 save_mime_part_info_free (info, TRUE);
2319 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2321 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2323 gdk_threads_leave (); /* CHECKED */
2330 save_mime_part_to_file (SaveMimePartInfo *info)
2332 GnomeVFSResult result;
2333 GnomeVFSHandle *handle;
2335 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2337 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0444);
2338 if (result == GNOME_VFS_OK) {
2339 stream = tny_vfs_stream_new (handle);
2340 tny_mime_part_decode_to_stream (pair->part, stream);
2341 g_object_unref (G_OBJECT (stream));
2342 g_object_unref (pair->part);
2343 g_slice_free (SaveMimePartPair, pair);
2344 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2345 info->result = TRUE;
2347 save_mime_part_info_free (info, FALSE);
2348 info->result = FALSE;
2351 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2356 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2358 gboolean is_ok = TRUE;
2359 gint replaced_files = 0;
2360 const GList *files = info->pairs;
2363 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2364 SaveMimePartPair *pair = iter->data;
2365 if (modest_maemo_utils_file_exists (pair->filename)) {
2369 if (replaced_files) {
2370 GtkWidget *confirm_overwrite_dialog;
2371 const gchar *message = (replaced_files == 1) ?
2372 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2373 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2374 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2377 gtk_widget_destroy (confirm_overwrite_dialog);
2381 save_mime_part_info_free (info, TRUE);
2383 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2384 _CS("sfil_ib_saving"));
2385 info->banner = g_object_ref (banner);
2386 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2387 g_object_unref (banner);
2394 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2396 gboolean clean_list = FALSE;
2397 ModestMsgViewWindowPrivate *priv;
2398 GList *files_to_save = NULL;
2399 GtkWidget *save_dialog = NULL;
2400 gchar *folder = NULL;
2401 gboolean canceled = FALSE;
2402 const gchar *filename = NULL;
2403 gchar *save_multiple_str = NULL;
2405 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2406 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2408 if (mime_parts == NULL) {
2409 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2410 if (mime_parts == NULL)
2415 /* prepare dialog */
2416 if (mime_parts->next == NULL) {
2417 /* only one attachment selected */
2418 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2419 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2420 filename = tny_mime_part_get_filename (mime_part);
2422 g_warning ("Tried to save a non-file attachment");
2426 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2427 g_list_length (mime_parts));
2430 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2431 GTK_FILE_CHOOSER_ACTION_SAVE);
2434 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2435 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2439 if (filename != NULL)
2440 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2443 /* if multiple, set multiple string */
2444 if (save_multiple_str) {
2445 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2449 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2450 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2452 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2453 hildon_banner_show_information
2454 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2458 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2459 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2461 if (tny_mime_part_is_attachment (mime_part)) {
2462 SaveMimePartPair *pair;
2464 if ((mime_parts->next != NULL) &&
2465 (tny_mime_part_get_filename (mime_part) == NULL))
2468 pair = g_slice_new0 (SaveMimePartPair);
2469 if (mime_parts->next == NULL) {
2470 pair->filename = g_strdup (chooser_uri);
2473 g_build_filename (chooser_uri,
2474 tny_mime_part_get_filename (mime_part), NULL);
2476 pair->part = g_object_ref (mime_part);
2477 files_to_save = g_list_prepend (files_to_save, pair);
2481 g_free (chooser_uri);
2484 gtk_widget_destroy (save_dialog);
2487 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2488 g_list_free (mime_parts);
2491 if (files_to_save != NULL) {
2492 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2493 info->pairs = files_to_save;
2494 info->result = TRUE;
2495 save_mime_parts_to_file_with_checks (info);
2500 show_remove_attachment_information (gpointer userdata)
2502 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2503 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2505 /* We're outside the main lock */
2506 gdk_threads_enter ();
2508 if (priv->remove_attachment_banner != NULL) {
2509 gtk_widget_destroy (priv->remove_attachment_banner);
2510 g_object_unref (priv->remove_attachment_banner);
2513 priv->remove_attachment_banner = g_object_ref (
2514 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2516 gdk_threads_leave ();
2522 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2524 ModestMsgViewWindowPrivate *priv;
2525 GList *mime_parts = NULL, *node;
2526 gchar *confirmation_message;
2530 /* TnyFolder *folder; */
2532 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2536 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2538 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2540 /* Remove already purged messages from mime parts list */
2542 while (node != NULL) {
2543 TnyMimePart *part = TNY_MIME_PART (node->data);
2544 if (tny_mime_part_is_purged (part)) {
2545 GList *deleted_node = node;
2546 node = g_list_next (node);
2547 g_object_unref (part);
2548 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2550 node = g_list_next (node);
2554 if (mime_parts == NULL)
2557 n_attachments = g_list_length (mime_parts);
2558 if (n_attachments == 1) {
2559 const gchar *filename;
2561 if (TNY_IS_MSG (mime_parts->data)) {
2563 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2564 filename = tny_header_get_subject (header);
2565 g_object_unref (header);
2566 if (filename == NULL)
2567 filename = _("mail_va_no_subject");
2569 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2571 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2573 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2574 "mcen_nc_purge_files_text",
2575 n_attachments), n_attachments);
2577 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2578 confirmation_message);
2579 g_free (confirmation_message);
2581 if (response != GTK_RESPONSE_OK)
2584 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2585 /* folder = tny_msg_get_folder (msg); */
2586 /* tny_msg_uncache_attachments (msg); */
2587 /* tny_folder_refresh (folder, NULL); */
2588 /* g_object_unref (folder); */
2590 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2591 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2592 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2595 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2596 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2597 tny_msg_rewrite_cache (msg);
2598 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2600 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2601 g_list_free (mime_parts);
2603 if (priv->purge_timeout > 0) {
2604 g_source_remove (priv->purge_timeout);
2605 priv->purge_timeout = 0;
2608 if (priv->remove_attachment_banner) {
2609 gtk_widget_destroy (priv->remove_attachment_banner);
2610 g_object_unref (priv->remove_attachment_banner);
2611 priv->remove_attachment_banner = NULL;
2619 update_window_title (ModestMsgViewWindow *window)
2621 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2623 TnyHeader *header = NULL;
2624 const gchar *subject = NULL;
2626 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2629 header = tny_msg_get_header (msg);
2630 subject = tny_header_get_subject (header);
2631 g_object_unref (msg);
2634 if ((subject == NULL)||(subject[0] == '\0'))
2635 subject = _("mail_va_no_subject");
2637 gtk_window_set_title (GTK_WINDOW (window), subject);
2641 static void on_move_focus (ModestMsgViewWindow *window,
2642 GtkDirectionType direction,
2645 GtkWidget *current_focus = NULL;
2647 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2648 if ((current_focus != NULL) &&
2649 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2650 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");