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"), NULL, 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);
865 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
866 update_window_title (MODEST_MSG_VIEW_WINDOW (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);
920 modest_msg_view_window_update_priority (window);
922 /* Check toolbar dimming rules */
923 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
925 return MODEST_WINDOW(window);
929 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
930 const gchar *modest_account_name,
931 const gchar *msg_uid)
933 ModestMsgViewWindow *window = NULL;
934 ModestMsgViewWindowPrivate *priv = NULL;
936 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
937 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
938 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
940 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
942 /* Remember that this is a search result,
943 * so we can disable some UI appropriately: */
944 priv->is_search_result = TRUE;
946 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
948 return MODEST_WINDOW(window);
952 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
953 const gchar *modest_account_name,
954 const gchar *msg_uid)
957 ModestMsgViewWindowPrivate *priv;
958 g_return_val_if_fail (msg, NULL);
960 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
961 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
962 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
963 modest_account_name, msg_uid);
965 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
967 return MODEST_WINDOW(obj);
970 void modest_msg_view_window_on_row_changed(
971 GtkTreeModel *header_model,
974 ModestMsgViewWindow *window){
975 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
978 void modest_msg_view_window_on_row_deleted(
979 GtkTreeModel *header_model,
981 ModestMsgViewWindow *window){
982 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
985 /* On insertions we check if the folder still has the message we are
986 * showing or do not. If do not, we do nothing. Which means we are still
987 * not attached to any header folder and thus next/prev buttons are
988 * still dimmed. Once the message that is shown by msg-view is found, the
989 * new model of header-view will be attached and the references will be set.
990 * On each further insertions dimming rules will be checked. However
991 * this requires extra CPU time at least works.
992 * (An message might be deleted from TnyFolder and thus will not be
993 * inserted into the model again for example if it is removed by the
994 * imap server and the header view is refreshed.)
996 void modest_msg_view_window_on_row_inserted(
997 GtkTreeModel *new_model,
998 GtkTreePath *tree_path,
999 GtkTreeIter *tree_iter,
1000 ModestMsgViewWindow *window){
1001 ModestMsgViewWindowPrivate *priv = NULL;
1002 TnyHeader *header = NULL;
1005 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1007 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1009 /* If we already has a model attached then the message shown by
1010 * msg-view is in it, and thus we do not need any actions but
1011 * to check the dimming rules.*/
1012 if(priv->header_model != NULL){
1013 gtk_tree_row_reference_free(priv->next_row_reference);
1014 priv->next_row_reference = gtk_tree_row_reference_copy(
1015 priv->row_reference);
1016 select_next_valid_row (priv->header_model,
1017 &(priv->next_row_reference), FALSE);
1018 modest_ui_actions_check_toolbar_dimming_rules (
1019 MODEST_WINDOW (window));
1023 /* Check if the newly inserted message is the same we are actually
1024 * showing. IF not, we should remain detached from the header model
1025 * and thus prev and next toolbarbuttons should remain dimmed. */
1026 gtk_tree_model_get (new_model, tree_iter,
1027 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1028 uid = modest_tny_folder_get_header_unique_id(header);
1029 if(!g_str_equal(priv->msg_uid, uid)){
1035 /* Setup row_reference for the actual msg. */
1036 priv->row_reference = gtk_tree_row_reference_new(
1037 new_model, tree_path);
1038 if(priv->row_reference == NULL){
1039 g_warning("No reference for msg header item.");
1043 /* Attach new_model and connect some callback to it to become able
1044 * to detect changes in header-view. */
1045 priv->header_model = g_object_ref(new_model);
1046 g_signal_connect (new_model, "row-changed",
1047 G_CALLBACK (modest_msg_view_window_on_row_changed),
1049 g_signal_connect (new_model, "row-deleted",
1050 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1052 g_signal_connect (new_model, "rows-reordered",
1053 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1056 /* Now set up next_row_reference. */
1057 priv->next_row_reference = gtk_tree_row_reference_copy(
1058 priv->row_reference);
1059 select_next_valid_row (priv->header_model,
1060 &(priv->next_row_reference), FALSE);
1062 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1065 void modest_msg_view_window_on_row_reordered(
1066 GtkTreeModel *header_model,
1070 ModestMsgViewWindow *window){
1071 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1074 /* The modest_msg_view_window_update_model_replaced implements update
1075 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1076 * actually belongs to the header-view is the same as the TnyFolder of
1077 * the message of msg-view or not. If they are different, there is
1078 * nothing to do. If they are the same, then the model has replaced and
1079 * the reference in msg-view shall be replaced from the old model to
1080 * the new model. In this case the view will be detached from it's
1081 * header folder. From this point the next/prev buttons are dimmed.
1083 void modest_msg_view_window_update_model_replaced(
1084 ModestHeaderViewObserver *observer,
1085 GtkTreeModel *model,
1086 const gchar *tny_folder_id){
1087 ModestMsgViewWindowPrivate *priv = NULL;
1088 ModestMsgViewWindow *window = NULL;
1090 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1091 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1093 window = MODEST_MSG_VIEW_WINDOW(observer);
1094 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1096 /* If there is an other folder in the header-view then we do
1097 * not care about it's model (msg list). Else if the
1098 * header-view shows the folder the msg shown by us is in, we
1099 * shall replace our model reference and make some check. */
1100 if(tny_folder_id == NULL ||
1101 !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 if(tny_folder_id == NULL)
1140 g_assert(model != NULL);
1142 /* Also we must connect to the new model for row insertions.
1143 * Only for insertions now. We will need other ones only after
1144 * the msg is show by msg-view is added to the new model. */
1145 priv->row_inserted_handler = g_signal_connect (
1146 model, "row-inserted",
1147 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1152 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1154 ModestMsgViewWindowPrivate *priv= NULL;
1156 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1157 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1159 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1163 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1165 ModestMsgViewWindowPrivate *priv= NULL;
1167 TnyHeader *header = NULL;
1168 GtkTreePath *path = NULL;
1171 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1172 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1174 /* If the message was not obtained from a treemodel,
1175 * for instance if it was opened directly by the search UI:
1177 if (priv->header_model == NULL) {
1178 msg = modest_msg_view_window_get_message (self);
1180 header = tny_msg_get_header (msg);
1181 g_object_unref (msg);
1186 /* Get iter of the currently selected message in the header view: */
1187 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1188 * instead of sometimes retrieving it from the header view?
1189 * Then we wouldn't be dependent on the message actually still being selected
1190 * in the header view. murrayc. */
1191 if (!gtk_tree_row_reference_valid (priv->row_reference))
1193 path = gtk_tree_row_reference_get_path (priv->row_reference);
1194 g_return_val_if_fail (path != NULL, NULL);
1195 gtk_tree_model_get_iter (priv->header_model,
1199 /* Get current message header */
1200 gtk_tree_model_get (priv->header_model, &iter,
1201 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1204 gtk_tree_path_free (path);
1209 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1211 ModestMsgView *msg_view;
1212 ModestMsgViewWindowPrivate *priv;
1214 g_return_val_if_fail (self, NULL);
1216 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1218 msg_view = MODEST_MSG_VIEW (priv->msg_view);
1220 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1224 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1226 ModestMsgViewWindowPrivate *priv;
1228 g_return_val_if_fail (self, NULL);
1230 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1232 return (const gchar*) priv->msg_uid;
1236 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1239 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1240 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1241 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1245 is_active = gtk_toggle_action_get_active (toggle);
1248 gtk_widget_show (priv->find_toolbar);
1249 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1251 gtk_widget_hide (priv->find_toolbar);
1254 /* update the toggle buttons status */
1255 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1256 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1257 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1258 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1263 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1264 ModestMsgViewWindow *obj)
1266 GtkToggleAction *toggle;
1267 ModestWindowPrivate *parent_priv;
1268 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1270 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1271 gtk_toggle_action_set_active (toggle, FALSE);
1275 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1276 ModestMsgViewWindow *obj)
1278 gchar *current_search;
1279 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1281 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1282 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1286 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1288 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1289 g_free (current_search);
1290 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1294 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1296 g_free (priv->last_search);
1297 priv->last_search = g_strdup (current_search);
1298 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1301 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1302 g_free (priv->last_search);
1303 priv->last_search = NULL;
1305 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1308 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1309 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1310 g_free (priv->last_search);
1311 priv->last_search = NULL;
1313 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1317 g_free (current_search);
1322 modest_msg_view_window_set_zoom (ModestWindow *window,
1325 ModestMsgViewWindowPrivate *priv;
1326 ModestWindowPrivate *parent_priv;
1327 GtkAction *action = NULL;
1328 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1330 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1332 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1333 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1334 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1336 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1337 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1339 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1343 modest_msg_view_window_get_zoom (ModestWindow *window)
1345 ModestMsgViewWindowPrivate *priv;
1347 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1349 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1350 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1354 modest_msg_view_window_zoom_plus (ModestWindow *window)
1356 ModestWindowPrivate *parent_priv;
1357 GtkRadioAction *zoom_radio_action;
1358 GSList *group, *node;
1360 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1361 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1362 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1364 group = gtk_radio_action_get_group (zoom_radio_action);
1366 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1367 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1371 for (node = group; node != NULL; node = g_slist_next (node)) {
1372 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1373 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1381 modest_msg_view_window_zoom_minus (ModestWindow *window)
1383 ModestWindowPrivate *parent_priv;
1384 GtkRadioAction *zoom_radio_action;
1385 GSList *group, *node;
1387 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1388 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1389 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1391 group = gtk_radio_action_get_group (zoom_radio_action);
1393 for (node = group; node != NULL; node = g_slist_next (node)) {
1394 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1395 if (node->next != NULL) {
1396 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1399 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1409 modest_msg_view_window_key_release_event (GtkWidget *window,
1413 if (event->type == GDK_KEY_RELEASE) {
1414 switch (event->keyval) {
1416 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1420 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1433 modest_msg_view_window_scroll_up (ModestWindow *window)
1435 ModestMsgViewWindowPrivate *priv;
1436 gboolean return_value;
1438 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1439 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1443 modest_msg_view_window_scroll_down (ModestWindow *window)
1445 ModestMsgViewWindowPrivate *priv;
1446 gboolean return_value;
1448 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1449 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1453 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1456 ModestMsgViewWindowPrivate *priv;
1457 GtkTreeIter tmp_iter;
1458 gboolean is_last_selected;
1460 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1461 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1463 /*if no model (so no rows at all), then virtually we are the last*/
1464 if (!priv->header_model)
1467 path = gtk_tree_row_reference_get_path (priv->row_reference);
1471 is_last_selected = TRUE;
1472 while (is_last_selected) {
1474 gtk_tree_path_next (path);
1475 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1477 gtk_tree_model_get (priv->header_model, &tmp_iter,
1478 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1480 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1481 is_last_selected = FALSE;
1483 gtk_tree_path_free (path);
1484 return is_last_selected;
1488 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1490 ModestMsgViewWindowPrivate *priv;
1492 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1493 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1495 return priv->header_model != NULL;
1499 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1501 ModestMsgViewWindowPrivate *priv;
1503 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1504 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1506 return priv->is_search_result;
1510 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1513 ModestMsgViewWindowPrivate *priv;
1514 gboolean is_first_selected;
1515 GtkTreeIter tmp_iter;
1516 /* gchar * path_string;*/
1518 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1519 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1521 /*if no model (so no rows at all), then virtually we are the first*/
1522 if (!priv->header_model)
1525 path = gtk_tree_row_reference_get_path (priv->row_reference);
1529 /* path_string = gtk_tree_path_to_string (path);
1530 is_first_selected = strcmp (path_string, "0");
1532 g_free (path_string);
1533 gtk_tree_path_free (path);
1535 return is_first_selected;*/
1537 is_first_selected = TRUE;
1538 while (is_first_selected) {
1540 if(!gtk_tree_path_prev (path))
1542 /* Here the 'if' is needless for logic, but let make sure
1543 * iter is valid for gtk_tree_model_get. */
1544 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1546 gtk_tree_model_get (priv->header_model, &tmp_iter,
1547 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1549 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1550 is_first_selected = FALSE;
1552 gtk_tree_path_free (path);
1553 return is_first_selected;
1557 * Reads the message whose summary item is @header. It takes care of
1558 * several things, among others:
1560 * If the message was not previously downloaded then ask the user
1561 * before downloading. If there is no connection launch the connection
1562 * dialog. Update toolbar dimming rules.
1564 * Returns: TRUE if the mail operation was started, otherwise if the
1565 * user do not want to download the message, or if the user do not
1566 * want to connect, then the operation is not issued
1569 message_reader (ModestMsgViewWindow *window,
1570 ModestMsgViewWindowPrivate *priv,
1572 GtkTreeRowReference *row_reference)
1574 ModestMailOperation *mail_op = NULL;
1575 ModestMailOperationTypeOperation op_type;
1576 gboolean already_showing = FALSE;
1577 ModestWindow *msg_window = NULL;
1578 ModestWindowMgr *mgr;
1580 g_return_val_if_fail (row_reference != NULL, FALSE);
1582 mgr = modest_runtime_get_window_mgr ();
1583 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1584 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1587 gtk_window_present (GTK_WINDOW (msg_window));
1588 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1592 /* Msg download completed */
1593 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1594 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1596 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1598 /* Ask the user if he wants to download the message if
1600 if (!tny_device_is_online (modest_runtime_get_device())) {
1601 TnyFolder *folder = NULL;
1602 GtkResponseType response;
1604 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1605 _("mcen_nc_get_msg"));
1606 if (response == GTK_RESPONSE_CANCEL)
1609 /* Offer the connection dialog if necessary */
1610 folder = tny_header_get_folder (header);
1612 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1613 TNY_FOLDER_STORE (folder))) {
1614 g_object_unref (folder);
1617 g_object_unref (folder);
1622 /* New mail operation */
1623 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1624 modest_ui_actions_get_msgs_full_error_handler,
1627 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1628 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1629 g_object_unref (mail_op);
1631 /* Update toolbar dimming rules */
1632 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1638 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1640 ModestMsgViewWindowPrivate *priv;
1641 GtkTreePath *path= NULL;
1642 GtkTreeIter tmp_iter;
1644 gboolean retval = TRUE;
1645 GtkTreeRowReference *row_reference = NULL;
1647 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1648 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1650 /* Update the next row reference if it's not valid. This could
1651 happen if for example the header which it was pointing to,
1652 was deleted. The best place to do it is in the row-deleted
1653 handler but the tinymail model do not work like the glib
1654 tree models and reports the deletion when the row is still
1656 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1657 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1658 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1659 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1662 if (priv->next_row_reference)
1663 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1667 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1669 gtk_tree_model_get_iter (priv->header_model,
1672 gtk_tree_path_free (path);
1674 gtk_tree_model_get (priv->header_model, &tmp_iter,
1675 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1678 /* Read the message & show it */
1679 if (!message_reader (window, priv, header, row_reference)) {
1681 gtk_tree_row_reference_free (row_reference);
1685 g_object_unref (header);
1691 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1693 ModestMsgViewWindowPrivate *priv = NULL;
1694 TnyHeader *header = NULL;
1696 GtkTreePath *path = NULL;
1697 GtkTreeRowReference *row_reference = NULL;
1699 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1700 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1702 /* Check that the model is not empty */
1703 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1706 /* Get the header */
1707 gtk_tree_model_get (priv->header_model,
1709 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1711 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1712 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1713 g_object_unref (header);
1714 return modest_msg_view_window_select_next_message (self);
1717 path = gtk_tree_model_get_path (priv->header_model, &iter);
1718 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1719 gtk_tree_path_free (path);
1721 /* Read the message & show it */
1722 message_reader (self, priv, header, row_reference);
1725 g_object_unref (header);
1731 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1733 ModestMsgViewWindowPrivate *priv = NULL;
1735 GtkTreeRowReference *row_reference = NULL;
1737 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1738 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1740 /* Return inmediatly if there is no header model */
1741 if (!priv->header_model)
1744 path = gtk_tree_row_reference_get_path (priv->row_reference);
1745 while (gtk_tree_path_prev (path)) {
1749 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1750 gtk_tree_model_get (priv->header_model, &iter,
1751 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1755 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1756 g_object_unref (header);
1760 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1761 /* Read the message & show it */
1762 if (!message_reader (window, priv, header, row_reference)) {
1763 gtk_tree_row_reference_free (row_reference);
1764 g_object_unref (header);
1768 gtk_tree_path_free (path);
1769 g_object_unref (header);
1774 gtk_tree_path_free (path);
1779 view_msg_cb (ModestMailOperation *mail_op,
1784 ModestMsgViewWindow *self = NULL;
1785 ModestMsgViewWindowPrivate *priv = NULL;
1786 GtkTreeRowReference *row_reference = NULL;
1788 /* If there was any error */
1789 row_reference = (GtkTreeRowReference *) user_data;
1790 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1791 gtk_tree_row_reference_free (row_reference);
1795 /* Get the window */
1796 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1797 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1798 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1800 /* Update the row reference */
1801 gtk_tree_row_reference_free (priv->row_reference);
1802 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1803 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1804 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1805 gtk_tree_row_reference_free (row_reference);
1807 /* Mark header as read */
1808 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1809 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1811 /* Set new message */
1812 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1813 modest_msg_view_window_update_priority (self);
1814 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1815 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1817 /* Set the new message uid of the window */
1818 if (priv->msg_uid) {
1819 g_free (priv->msg_uid);
1820 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1823 /* Notify the observers */
1824 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1825 0, priv->header_model, priv->row_reference);
1827 /* Free new references */
1828 g_object_unref (self);
1832 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1834 ModestMsgViewWindowPrivate *priv;
1836 TnyFolderType folder_type;
1838 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1840 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1842 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1846 folder = tny_msg_get_folder (msg);
1848 folder_type = tny_folder_get_folder_type (folder);
1849 g_object_unref (folder);
1851 g_object_unref (msg);
1859 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1861 ModestMsgViewWindowPrivate *priv;
1862 TnyHeaderFlags flags = 0;
1864 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1866 if (priv->header_model) {
1869 GtkTreePath *path = NULL;
1871 path = gtk_tree_row_reference_get_path (priv->row_reference);
1872 g_return_if_fail (path != NULL);
1873 gtk_tree_model_get_iter (priv->header_model,
1875 gtk_tree_row_reference_get_path (priv->row_reference));
1877 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1879 flags = tny_header_get_flags (header);
1880 gtk_tree_path_free (path);
1883 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1888 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1890 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1891 ModestWindowPrivate *parent_priv;
1892 ModestWindowMgr *mgr;
1893 gboolean is_fullscreen;
1894 GtkAction *fs_toggle_action;
1897 mgr = modest_runtime_get_window_mgr ();
1898 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1900 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1902 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1903 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1904 if (is_fullscreen != active) {
1905 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1914 set_homogeneous (GtkWidget *widget,
1917 if (GTK_IS_TOOL_ITEM (widget)) {
1918 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1919 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1924 modest_msg_view_window_show_toolbar (ModestWindow *self,
1925 gboolean show_toolbar)
1927 ModestMsgViewWindowPrivate *priv = NULL;
1928 ModestWindowPrivate *parent_priv;
1929 GtkWidget *reply_button = NULL, *menu = NULL;
1930 GtkWidget *placeholder = NULL;
1932 const gchar *action_name;
1935 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1936 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1938 /* Set optimized view status */
1939 priv->optimized_view = !show_toolbar;
1941 if (!parent_priv->toolbar) {
1942 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1944 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1946 /* Set homogeneous toolbar */
1947 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1948 set_homogeneous, NULL);
1950 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1951 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1952 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1953 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1954 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1955 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1956 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1957 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1959 /* Add ProgressBar (Transfer toolbar) */
1960 priv->progress_bar = modest_progress_bar_widget_new ();
1961 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1962 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1963 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1964 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1965 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1967 /* Connect cancel 'clicked' signal to abort progress mode */
1968 g_signal_connect(priv->cancel_toolitem, "clicked",
1969 G_CALLBACK(cancel_progressbar),
1972 /* Add it to the observers list */
1973 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1976 hildon_window_add_toolbar (HILDON_WINDOW (self),
1977 GTK_TOOLBAR (parent_priv->toolbar));
1980 /* Set reply button tap and hold menu */
1981 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1982 "/ToolBar/ToolbarMessageReply");
1983 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1984 "/ToolbarReplyCSM");
1985 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1989 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1990 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1991 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1993 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1994 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1997 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1998 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2001 /* Update also the actions (to update the toggles in the
2002 menus), we have to do it manually because some other window
2003 of the same time could have changed it (remember that the
2004 toolbar fullscreen mode is shared by all the windows of the
2006 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2007 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2009 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2011 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2012 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2017 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2019 ModestMsgViewWindow *window)
2021 if (!GTK_WIDGET_VISIBLE (window))
2024 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2028 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2030 ModestMsgViewWindowPrivate *priv;
2032 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2033 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2035 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2039 cancel_progressbar (GtkToolButton *toolbutton,
2040 ModestMsgViewWindow *self)
2043 ModestMsgViewWindowPrivate *priv;
2045 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2047 /* Get operation observers and cancel its current operation */
2048 tmp = priv->progress_widgets;
2050 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2051 tmp=g_slist_next(tmp);
2055 observers_empty (ModestMsgViewWindow *self)
2058 ModestMsgViewWindowPrivate *priv;
2059 gboolean is_empty = TRUE;
2060 guint pending_ops = 0;
2062 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2063 tmp = priv->progress_widgets;
2065 /* Check all observers */
2066 while (tmp && is_empty) {
2067 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2068 is_empty = pending_ops == 0;
2070 tmp = g_slist_next(tmp);
2077 on_account_removed (TnyAccountStore *account_store,
2078 TnyAccount *account,
2081 /* Do nothing if it's a transport account, because we only
2082 show the messages of a store account */
2083 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2084 const gchar *parent_acc = NULL;
2085 const gchar *our_acc = NULL;
2087 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2088 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2090 /* Close this window if I'm showing a message of the removed account */
2091 if (strcmp (parent_acc, our_acc) == 0)
2092 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2097 on_queue_changed (ModestMailOperationQueue *queue,
2098 ModestMailOperation *mail_op,
2099 ModestMailOperationQueueNotification type,
2100 ModestMsgViewWindow *self)
2103 ModestMsgViewWindowPrivate *priv;
2104 ModestMailOperationTypeOperation op_type;
2105 ModestToolBarModes mode;
2107 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2108 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2110 /* If this operations was created by another window, do nothing */
2111 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2114 /* Get toolbar mode from operation id*/
2115 op_type = modest_mail_operation_get_type_operation (mail_op);
2117 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2118 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2119 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2120 mode = TOOLBAR_MODE_TRANSFER;
2123 mode = TOOLBAR_MODE_NORMAL;
2127 /* Add operation observers and change toolbar if neccessary*/
2128 tmp = priv->progress_widgets;
2130 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2131 if (mode == TOOLBAR_MODE_TRANSFER) {
2132 /* Enable transfer toolbar mode */
2133 set_toolbar_transfer_mode(self);
2135 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2137 tmp = g_slist_next (tmp);
2142 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2143 if (mode == TOOLBAR_MODE_TRANSFER) {
2145 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2147 tmp = g_slist_next (tmp);
2151 /* If no more operations are being observed, NORMAL mode is enabled again */
2152 if (observers_empty (self)) {
2153 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2161 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2163 ModestMsgViewWindowPrivate *priv;
2164 GList *selected_attachments = NULL;
2166 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2167 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2169 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2171 return selected_attachments;
2175 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2177 ModestMsgViewWindowPrivate *priv;
2178 const gchar *msg_uid;
2179 gchar *attachment_uid = NULL;
2180 gint attachment_index = 0;
2183 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2184 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2185 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2187 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2188 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2189 attachment_index = g_list_index (attachments, mime_part);
2190 g_list_free (attachments);
2192 if (msg_uid && attachment_index >= 0) {
2193 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2196 if (mime_part == NULL) {
2197 gboolean error = FALSE;
2198 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2199 if (selected_attachments == NULL) {
2201 } else if (g_list_length (selected_attachments) > 1) {
2202 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2205 mime_part = (TnyMimePart *) selected_attachments->data;
2206 g_object_ref (mime_part);
2208 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2209 g_list_free (selected_attachments);
2214 g_object_ref (mime_part);
2217 if (tny_mime_part_is_purged (mime_part)) {
2218 g_object_unref (mime_part);
2222 if (!TNY_IS_MSG (mime_part)) {
2223 gchar *filepath = NULL;
2224 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2225 TnyFsStream *temp_stream = NULL;
2226 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2229 const gchar *content_type;
2230 content_type = tny_mime_part_get_content_type (mime_part);
2231 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2233 modest_platform_activate_file (filepath, content_type);
2234 g_object_unref (temp_stream);
2236 /* NOTE: files in the temporary area will be automatically
2237 * cleaned after some time if they are no longer in use */
2240 /* message attachment */
2241 TnyHeader *header = NULL;
2242 ModestWindowMgr *mgr;
2243 ModestWindow *msg_win = NULL;
2246 header = tny_msg_get_header (TNY_MSG (mime_part));
2247 mgr = modest_runtime_get_window_mgr ();
2248 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2251 if (msg_win) /* there is already a window for this uid; top it */
2252 gtk_window_present (GTK_WINDOW(msg_win));
2254 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2255 * thus, we don't do anything */
2256 g_warning ("window for is already being created");
2258 /* it's not found, so create a new window for it */
2259 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2260 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2262 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2263 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2264 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2265 modest_window_get_zoom (MODEST_WINDOW (window)));
2266 modest_window_mgr_register_window (mgr, msg_win);
2267 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2268 gtk_widget_show_all (GTK_WIDGET (msg_win));
2271 g_object_unref (mime_part);
2287 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2288 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2289 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2290 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2293 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2297 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2298 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2299 g_free (pair->filename);
2300 g_object_unref (pair->part);
2301 g_slice_free (SaveMimePartPair, pair);
2303 g_list_free (info->pairs);
2306 gtk_widget_destroy (info->banner);
2307 g_object_unref (info->banner);
2308 g_slice_free (SaveMimePartInfo, info);
2313 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2315 if (info->pairs != NULL) {
2316 save_mime_part_to_file (info);
2319 result = info->result;
2321 /* This is a GDK lock because we are an idle callback and
2322 * hildon_banner_show_information is or does Gtk+ code */
2324 gdk_threads_enter (); /* CHECKED */
2325 save_mime_part_info_free (info, TRUE);
2327 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2329 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2331 gdk_threads_leave (); /* CHECKED */
2338 save_mime_part_to_file (SaveMimePartInfo *info)
2340 GnomeVFSResult result;
2341 GnomeVFSHandle *handle;
2343 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2345 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0444);
2346 if (result == GNOME_VFS_OK) {
2347 stream = tny_vfs_stream_new (handle);
2348 tny_mime_part_decode_to_stream (pair->part, stream);
2349 g_object_unref (G_OBJECT (stream));
2350 g_object_unref (pair->part);
2351 g_slice_free (SaveMimePartPair, pair);
2352 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2353 info->result = TRUE;
2355 save_mime_part_info_free (info, FALSE);
2356 info->result = FALSE;
2359 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2364 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2366 gboolean is_ok = TRUE;
2367 gint replaced_files = 0;
2368 const GList *files = info->pairs;
2371 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2372 SaveMimePartPair *pair = iter->data;
2373 if (modest_maemo_utils_file_exists (pair->filename)) {
2377 if (replaced_files) {
2378 GtkWidget *confirm_overwrite_dialog;
2379 const gchar *message = (replaced_files == 1) ?
2380 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2381 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2382 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2385 gtk_widget_destroy (confirm_overwrite_dialog);
2389 save_mime_part_info_free (info, TRUE);
2391 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2392 _CS("sfil_ib_saving"));
2393 info->banner = g_object_ref (banner);
2394 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2395 g_object_unref (banner);
2402 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2404 gboolean clean_list = FALSE;
2405 ModestMsgViewWindowPrivate *priv;
2406 GList *files_to_save = NULL;
2407 GtkWidget *save_dialog = NULL;
2408 gchar *folder = NULL;
2409 gboolean canceled = FALSE;
2410 const gchar *filename = NULL;
2411 gchar *save_multiple_str = NULL;
2413 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2414 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2416 if (mime_parts == NULL) {
2417 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2418 if (mime_parts == NULL)
2423 /* prepare dialog */
2424 if (mime_parts->next == NULL) {
2425 /* only one attachment selected */
2426 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2427 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2428 filename = tny_mime_part_get_filename (mime_part);
2430 g_warning ("Tried to save a non-file attachment");
2434 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2435 g_list_length (mime_parts));
2438 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2439 GTK_FILE_CHOOSER_ACTION_SAVE);
2442 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2443 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2447 if (filename != NULL)
2448 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2451 /* if multiple, set multiple string */
2452 if (save_multiple_str) {
2453 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2457 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2458 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2460 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2461 hildon_banner_show_information
2462 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2466 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2467 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2469 if (tny_mime_part_is_attachment (mime_part)) {
2470 SaveMimePartPair *pair;
2472 if ((mime_parts->next != NULL) &&
2473 (tny_mime_part_get_filename (mime_part) == NULL))
2476 pair = g_slice_new0 (SaveMimePartPair);
2477 if (mime_parts->next == NULL) {
2478 pair->filename = g_strdup (chooser_uri);
2481 g_build_filename (chooser_uri,
2482 tny_mime_part_get_filename (mime_part), NULL);
2484 pair->part = g_object_ref (mime_part);
2485 files_to_save = g_list_prepend (files_to_save, pair);
2489 g_free (chooser_uri);
2492 gtk_widget_destroy (save_dialog);
2495 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2496 g_list_free (mime_parts);
2499 if (files_to_save != NULL) {
2500 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2501 info->pairs = files_to_save;
2502 info->result = TRUE;
2503 save_mime_parts_to_file_with_checks (info);
2508 show_remove_attachment_information (gpointer userdata)
2510 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2511 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2513 if (priv->remove_attachment_banner != NULL) {
2514 gtk_widget_destroy (priv->remove_attachment_banner);
2515 g_object_unref (priv->remove_attachment_banner);
2518 priv->remove_attachment_banner = g_object_ref (
2519 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2525 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2527 ModestMsgViewWindowPrivate *priv;
2528 GList *mime_parts = NULL, *node;
2529 gchar *confirmation_message;
2533 /* TnyFolder *folder; */
2535 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2536 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2539 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2541 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2543 /* Remove already purged messages from mime parts list */
2545 while (node != NULL) {
2546 TnyMimePart *part = TNY_MIME_PART (node->data);
2547 if (tny_mime_part_is_purged (part)) {
2548 GList *deleted_node = node;
2549 node = g_list_next (node);
2550 g_object_unref (part);
2551 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2553 node = g_list_next (node);
2557 if (mime_parts == NULL)
2560 n_attachments = g_list_length (mime_parts);
2561 if (n_attachments == 1) {
2562 const gchar *filename;
2564 if (TNY_IS_MSG (mime_parts->data)) {
2566 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2567 filename = tny_header_get_subject (header);
2568 g_object_unref (header);
2569 if (filename == NULL)
2570 filename = _("mail_va_no_subject");
2572 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2574 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2576 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2577 "mcen_nc_purge_files_text",
2578 n_attachments), n_attachments);
2580 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2581 confirmation_message);
2582 g_free (confirmation_message);
2584 if (response != GTK_RESPONSE_OK)
2587 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2588 /* folder = tny_msg_get_folder (msg); */
2589 /* tny_msg_uncache_attachments (msg); */
2590 /* tny_folder_refresh (folder, NULL); */
2591 /* g_object_unref (folder); */
2593 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2594 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2595 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2598 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2599 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2600 tny_msg_rewrite_cache (msg);
2601 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2603 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2604 g_list_free (mime_parts);
2606 if (priv->purge_timeout > 0) {
2607 g_source_remove (priv->purge_timeout);
2608 priv->purge_timeout = 0;
2611 if (priv->remove_attachment_banner) {
2612 gtk_widget_destroy (priv->remove_attachment_banner);
2613 g_object_unref (priv->remove_attachment_banner);
2614 priv->remove_attachment_banner = NULL;
2622 update_window_title (ModestMsgViewWindow *window)
2624 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2626 TnyHeader *header = NULL;
2627 const gchar *subject = NULL;
2629 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2632 header = tny_msg_get_header (msg);
2633 subject = tny_header_get_subject (header);
2634 g_object_unref (msg);
2637 if ((subject == NULL)||(subject[0] == '\0'))
2638 subject = _("mail_va_no_subject");
2640 gtk_window_set_title (GTK_WINDOW (window), subject);
2644 static void on_move_focus (ModestMsgViewWindow *window,
2645 GtkDirectionType direction,
2648 GtkWidget *current_focus = NULL;
2650 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2651 if ((current_focus != NULL) &&
2652 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2653 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");