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);
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);
918 modest_msg_view_window_update_priority (window);
920 /* Check toolbar dimming rules */
921 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
923 return MODEST_WINDOW(window);
927 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
928 const gchar *modest_account_name,
929 const gchar *msg_uid)
931 ModestMsgViewWindow *window = NULL;
932 ModestMsgViewWindowPrivate *priv = NULL;
934 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
935 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
936 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
938 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
940 /* Remember that this is a search result,
941 * so we can disable some UI appropriately: */
942 priv->is_search_result = TRUE;
944 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
946 return MODEST_WINDOW(window);
950 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
951 const gchar *modest_account_name,
952 const gchar *msg_uid)
955 ModestMsgViewWindowPrivate *priv;
956 g_return_val_if_fail (msg, NULL);
958 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
959 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
960 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
961 modest_account_name, msg_uid);
963 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
965 return MODEST_WINDOW(obj);
968 void modest_msg_view_window_on_row_changed(
969 GtkTreeModel *header_model,
972 ModestMsgViewWindow *window){
973 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
976 void modest_msg_view_window_on_row_deleted(
977 GtkTreeModel *header_model,
979 ModestMsgViewWindow *window){
980 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
983 /* On insertions we check if the folder still has the message we are
984 * showing or do not. If do not, we do nothing. Which means we are still
985 * not attached to any header folder and thus next/prev buttons are
986 * still dimmed. Once the message that is shown by msg-view is found, the
987 * new model of header-view will be attached and the references will be set.
988 * On each further insertions dimming rules will be checked. However
989 * this requires extra CPU time at least works.
990 * (An message might be deleted from TnyFolder and thus will not be
991 * inserted into the model again for example if it is removed by the
992 * imap server and the header view is refreshed.)
994 void modest_msg_view_window_on_row_inserted(
995 GtkTreeModel *new_model,
996 GtkTreePath *tree_path,
997 GtkTreeIter *tree_iter,
998 ModestMsgViewWindow *window){
999 ModestMsgViewWindowPrivate *priv = NULL;
1000 TnyHeader *header = NULL;
1003 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1005 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1007 /* If we already has a model attached then the message shown by
1008 * msg-view is in it, and thus we do not need any actions but
1009 * to check the dimming rules.*/
1010 if(priv->header_model != NULL){
1011 gtk_tree_row_reference_free(priv->next_row_reference);
1012 priv->next_row_reference = gtk_tree_row_reference_copy(
1013 priv->row_reference);
1014 select_next_valid_row (priv->header_model,
1015 &(priv->next_row_reference), FALSE);
1016 modest_ui_actions_check_toolbar_dimming_rules (
1017 MODEST_WINDOW (window));
1021 /* Check if the newly inserted message is the same we are actually
1022 * showing. IF not, we should remain detached from the header model
1023 * and thus prev and next toolbarbuttons should remain dimmed. */
1024 gtk_tree_model_get (new_model, tree_iter,
1025 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1026 uid = modest_tny_folder_get_header_unique_id(header);
1027 if(!g_str_equal(priv->msg_uid, uid)){
1033 /* Setup row_reference for the actual msg. */
1034 priv->row_reference = gtk_tree_row_reference_new(
1035 new_model, tree_path);
1036 if(priv->row_reference == NULL){
1037 g_warning("No reference for msg header item.");
1041 /* Attach new_model and connect some callback to it to become able
1042 * to detect changes in header-view. */
1043 priv->header_model = g_object_ref(new_model);
1044 g_signal_connect (new_model, "row-changed",
1045 G_CALLBACK (modest_msg_view_window_on_row_changed),
1047 g_signal_connect (new_model, "row-deleted",
1048 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1050 g_signal_connect (new_model, "rows-reordered",
1051 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1054 /* Now set up next_row_reference. */
1055 priv->next_row_reference = gtk_tree_row_reference_copy(
1056 priv->row_reference);
1057 select_next_valid_row (priv->header_model,
1058 &(priv->next_row_reference), FALSE);
1060 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1063 void modest_msg_view_window_on_row_reordered(
1064 GtkTreeModel *header_model,
1068 ModestMsgViewWindow *window){
1069 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1072 /* The modest_msg_view_window_update_model_replaced implements update
1073 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1074 * actually belongs to the header-view is the same as the TnyFolder of
1075 * the message of msg-view or not. If they are different, there is
1076 * nothing to do. If they are the same, then the model has replaced and
1077 * the reference in msg-view shall be replaced from the old model to
1078 * the new model. In this case the view will be detached from it's
1079 * header folder. From this point the next/prev buttons are dimmed.
1081 void modest_msg_view_window_update_model_replaced(
1082 ModestHeaderViewObserver *observer,
1083 GtkTreeModel *model,
1084 const gchar *tny_folder_id){
1085 ModestMsgViewWindowPrivate *priv = NULL;
1086 ModestMsgViewWindow *window = NULL;
1088 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1089 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1091 window = MODEST_MSG_VIEW_WINDOW(observer);
1092 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1094 /* If there is an other folder in the header-view then we do
1095 * not care about it's model (msg list). Else if the
1096 * header-view shows the folder the msg shown by us is in, we
1097 * shall replace our model reference and make some check. */
1098 if(tny_folder_id == NULL ||
1099 !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 if(tny_folder_id == NULL)
1138 g_assert(model != NULL);
1140 /* Also we must connect to the new model for row insertions.
1141 * Only for insertions now. We will need other ones only after
1142 * the msg is show by msg-view is added to the new model. */
1143 priv->row_inserted_handler = g_signal_connect (
1144 model, "row-inserted",
1145 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1150 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1152 ModestMsgViewWindowPrivate *priv= NULL;
1154 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1155 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1157 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1161 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1163 ModestMsgViewWindowPrivate *priv= NULL;
1165 TnyHeader *header = NULL;
1166 GtkTreePath *path = NULL;
1169 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1170 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1172 /* If the message was not obtained from a treemodel,
1173 * for instance if it was opened directly by the search UI:
1175 if (priv->header_model == NULL) {
1176 msg = modest_msg_view_window_get_message (self);
1178 header = tny_msg_get_header (msg);
1179 g_object_unref (msg);
1184 /* Get iter of the currently selected message in the header view: */
1185 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1186 * instead of sometimes retrieving it from the header view?
1187 * Then we wouldn't be dependent on the message actually still being selected
1188 * in the header view. murrayc. */
1189 if (!gtk_tree_row_reference_valid (priv->row_reference))
1191 path = gtk_tree_row_reference_get_path (priv->row_reference);
1192 g_return_val_if_fail (path != NULL, NULL);
1193 gtk_tree_model_get_iter (priv->header_model,
1197 /* Get current message header */
1198 gtk_tree_model_get (priv->header_model, &iter,
1199 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1202 gtk_tree_path_free (path);
1207 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1209 ModestMsgView *msg_view;
1210 ModestMsgViewWindowPrivate *priv;
1212 g_return_val_if_fail (self, NULL);
1214 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1216 msg_view = MODEST_MSG_VIEW (priv->msg_view);
1218 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1222 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1224 ModestMsgViewWindowPrivate *priv;
1226 g_return_val_if_fail (self, NULL);
1228 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1230 return (const gchar*) priv->msg_uid;
1234 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1237 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1238 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1239 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1243 is_active = gtk_toggle_action_get_active (toggle);
1246 gtk_widget_show (priv->find_toolbar);
1247 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1249 gtk_widget_hide (priv->find_toolbar);
1252 /* update the toggle buttons status */
1253 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1254 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1255 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1256 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1261 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1262 ModestMsgViewWindow *obj)
1264 GtkToggleAction *toggle;
1265 ModestWindowPrivate *parent_priv;
1266 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1268 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1269 gtk_toggle_action_set_active (toggle, FALSE);
1273 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1274 ModestMsgViewWindow *obj)
1276 gchar *current_search;
1277 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1279 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1280 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1284 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1286 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1287 g_free (current_search);
1288 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1292 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1294 g_free (priv->last_search);
1295 priv->last_search = g_strdup (current_search);
1296 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1299 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1300 g_free (priv->last_search);
1301 priv->last_search = NULL;
1303 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1306 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1307 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1308 g_free (priv->last_search);
1309 priv->last_search = NULL;
1311 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1315 g_free (current_search);
1320 modest_msg_view_window_set_zoom (ModestWindow *window,
1323 ModestMsgViewWindowPrivate *priv;
1324 ModestWindowPrivate *parent_priv;
1325 GtkAction *action = NULL;
1326 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1328 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1330 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1331 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1332 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1334 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1335 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1337 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1341 modest_msg_view_window_get_zoom (ModestWindow *window)
1343 ModestMsgViewWindowPrivate *priv;
1345 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1347 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1348 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1352 modest_msg_view_window_zoom_plus (ModestWindow *window)
1354 ModestWindowPrivate *parent_priv;
1355 GtkRadioAction *zoom_radio_action;
1356 GSList *group, *node;
1358 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1359 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1360 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1362 group = gtk_radio_action_get_group (zoom_radio_action);
1364 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1365 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1369 for (node = group; node != NULL; node = g_slist_next (node)) {
1370 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1371 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1379 modest_msg_view_window_zoom_minus (ModestWindow *window)
1381 ModestWindowPrivate *parent_priv;
1382 GtkRadioAction *zoom_radio_action;
1383 GSList *group, *node;
1385 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1386 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1387 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1389 group = gtk_radio_action_get_group (zoom_radio_action);
1391 for (node = group; node != NULL; node = g_slist_next (node)) {
1392 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1393 if (node->next != NULL) {
1394 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1397 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1407 modest_msg_view_window_key_release_event (GtkWidget *window,
1411 if (event->type == GDK_KEY_RELEASE) {
1412 switch (event->keyval) {
1414 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1418 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1431 modest_msg_view_window_scroll_up (ModestWindow *window)
1433 ModestMsgViewWindowPrivate *priv;
1434 gboolean return_value;
1436 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1437 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1441 modest_msg_view_window_scroll_down (ModestWindow *window)
1443 ModestMsgViewWindowPrivate *priv;
1444 gboolean return_value;
1446 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1447 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1451 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1454 ModestMsgViewWindowPrivate *priv;
1455 GtkTreeIter tmp_iter;
1456 gboolean is_last_selected;
1458 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1459 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1461 /*if no model (so no rows at all), then virtually we are the last*/
1462 if (!priv->header_model)
1465 path = gtk_tree_row_reference_get_path (priv->row_reference);
1469 is_last_selected = TRUE;
1470 while (is_last_selected) {
1472 gtk_tree_path_next (path);
1473 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1475 gtk_tree_model_get (priv->header_model, &tmp_iter,
1476 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1478 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1479 is_last_selected = FALSE;
1481 gtk_tree_path_free (path);
1482 return is_last_selected;
1486 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1488 ModestMsgViewWindowPrivate *priv;
1490 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1491 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1493 return priv->header_model != NULL;
1497 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1499 ModestMsgViewWindowPrivate *priv;
1501 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1502 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1504 return priv->is_search_result;
1508 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1511 ModestMsgViewWindowPrivate *priv;
1512 gboolean is_first_selected;
1513 GtkTreeIter tmp_iter;
1514 /* gchar * path_string;*/
1516 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1517 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1519 /*if no model (so no rows at all), then virtually we are the first*/
1520 if (!priv->header_model)
1523 path = gtk_tree_row_reference_get_path (priv->row_reference);
1527 /* path_string = gtk_tree_path_to_string (path);
1528 is_first_selected = strcmp (path_string, "0");
1530 g_free (path_string);
1531 gtk_tree_path_free (path);
1533 return is_first_selected;*/
1535 is_first_selected = TRUE;
1536 while (is_first_selected) {
1538 if(!gtk_tree_path_prev (path))
1540 /* Here the 'if' is needless for logic, but let make sure
1541 * iter is valid for gtk_tree_model_get. */
1542 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1544 gtk_tree_model_get (priv->header_model, &tmp_iter,
1545 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1547 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1548 is_first_selected = FALSE;
1550 gtk_tree_path_free (path);
1551 return is_first_selected;
1555 * Reads the message whose summary item is @header. It takes care of
1556 * several things, among others:
1558 * If the message was not previously downloaded then ask the user
1559 * before downloading. If there is no connection launch the connection
1560 * dialog. Update toolbar dimming rules.
1562 * Returns: TRUE if the mail operation was started, otherwise if the
1563 * user do not want to download the message, or if the user do not
1564 * want to connect, then the operation is not issued
1567 message_reader (ModestMsgViewWindow *window,
1568 ModestMsgViewWindowPrivate *priv,
1570 GtkTreeRowReference *row_reference)
1572 ModestMailOperation *mail_op = NULL;
1573 ModestMailOperationTypeOperation op_type;
1574 gboolean already_showing = FALSE;
1575 ModestWindow *msg_window = NULL;
1576 ModestWindowMgr *mgr;
1578 g_return_val_if_fail (row_reference != NULL, FALSE);
1580 mgr = modest_runtime_get_window_mgr ();
1581 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1582 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1585 gtk_window_present (GTK_WINDOW (msg_window));
1586 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1590 /* Msg download completed */
1591 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1592 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1594 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1596 /* Ask the user if he wants to download the message if
1598 if (!tny_device_is_online (modest_runtime_get_device())) {
1599 TnyFolder *folder = NULL;
1600 GtkResponseType response;
1602 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1603 _("mcen_nc_get_msg"));
1604 if (response == GTK_RESPONSE_CANCEL)
1607 /* Offer the connection dialog if necessary */
1608 folder = tny_header_get_folder (header);
1610 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1611 TNY_FOLDER_STORE (folder))) {
1612 g_object_unref (folder);
1615 g_object_unref (folder);
1620 /* New mail operation */
1621 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1622 modest_ui_actions_get_msgs_full_error_handler,
1625 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1626 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1627 g_object_unref (mail_op);
1629 /* Update toolbar dimming rules */
1630 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1636 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1638 ModestMsgViewWindowPrivate *priv;
1639 GtkTreePath *path= NULL;
1640 GtkTreeIter tmp_iter;
1642 gboolean retval = TRUE;
1643 GtkTreeRowReference *row_reference = NULL;
1645 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1646 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1648 /* Update the next row reference if it's not valid. This could
1649 happen if for example the header which it was pointing to,
1650 was deleted. The best place to do it is in the row-deleted
1651 handler but the tinymail model do not work like the glib
1652 tree models and reports the deletion when the row is still
1654 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1655 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1656 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1657 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1660 if (priv->next_row_reference)
1661 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1665 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1667 gtk_tree_model_get_iter (priv->header_model,
1670 gtk_tree_path_free (path);
1672 gtk_tree_model_get (priv->header_model, &tmp_iter,
1673 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1676 /* Read the message & show it */
1677 if (!message_reader (window, priv, header, row_reference)) {
1679 gtk_tree_row_reference_free (row_reference);
1683 g_object_unref (header);
1689 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1691 ModestMsgViewWindowPrivate *priv = NULL;
1692 TnyHeader *header = NULL;
1694 GtkTreePath *path = NULL;
1695 GtkTreeRowReference *row_reference = NULL;
1697 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1698 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1700 /* Check that the model is not empty */
1701 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1704 /* Get the header */
1705 gtk_tree_model_get (priv->header_model,
1707 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1709 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1710 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1711 g_object_unref (header);
1712 return modest_msg_view_window_select_next_message (self);
1715 path = gtk_tree_model_get_path (priv->header_model, &iter);
1716 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1717 gtk_tree_path_free (path);
1719 /* Read the message & show it */
1720 message_reader (self, priv, header, row_reference);
1723 g_object_unref (header);
1729 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1731 ModestMsgViewWindowPrivate *priv = NULL;
1733 GtkTreeRowReference *row_reference = NULL;
1735 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1736 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1738 /* Return inmediatly if there is no header model */
1739 if (!priv->header_model)
1742 path = gtk_tree_row_reference_get_path (priv->row_reference);
1743 while (gtk_tree_path_prev (path)) {
1747 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1748 gtk_tree_model_get (priv->header_model, &iter,
1749 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1753 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1754 g_object_unref (header);
1758 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1759 /* Read the message & show it */
1760 if (!message_reader (window, priv, header, row_reference)) {
1761 gtk_tree_row_reference_free (row_reference);
1762 g_object_unref (header);
1766 gtk_tree_path_free (path);
1767 g_object_unref (header);
1772 gtk_tree_path_free (path);
1777 view_msg_cb (ModestMailOperation *mail_op,
1782 ModestMsgViewWindow *self = NULL;
1783 ModestMsgViewWindowPrivate *priv = NULL;
1784 GtkTreeRowReference *row_reference = NULL;
1786 /* If there was any error */
1787 row_reference = (GtkTreeRowReference *) user_data;
1788 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1789 gtk_tree_row_reference_free (row_reference);
1793 /* Get the window */
1794 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1795 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1796 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1798 /* Update the row reference */
1799 gtk_tree_row_reference_free (priv->row_reference);
1800 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1801 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1802 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1803 gtk_tree_row_reference_free (row_reference);
1805 /* Mark header as read */
1806 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1807 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1809 /* Set new message */
1810 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1811 modest_msg_view_window_update_priority (self);
1812 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1813 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1815 /* Set the new message uid of the window */
1816 if (priv->msg_uid) {
1817 g_free (priv->msg_uid);
1818 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1821 /* Notify the observers */
1822 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1823 0, priv->header_model, priv->row_reference);
1825 /* Free new references */
1826 g_object_unref (self);
1830 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1832 ModestMsgViewWindowPrivate *priv;
1834 TnyFolderType folder_type;
1836 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1838 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1840 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1844 folder = tny_msg_get_folder (msg);
1846 folder_type = tny_folder_get_folder_type (folder);
1847 g_object_unref (folder);
1849 g_object_unref (msg);
1857 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1859 ModestMsgViewWindowPrivate *priv;
1860 TnyHeaderFlags flags = 0;
1862 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1864 if (priv->header_model) {
1867 GtkTreePath *path = NULL;
1869 path = gtk_tree_row_reference_get_path (priv->row_reference);
1870 g_return_if_fail (path != NULL);
1871 gtk_tree_model_get_iter (priv->header_model,
1873 gtk_tree_row_reference_get_path (priv->row_reference));
1875 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1877 flags = tny_header_get_flags (header);
1878 gtk_tree_path_free (path);
1881 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1886 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1888 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1889 ModestWindowPrivate *parent_priv;
1890 ModestWindowMgr *mgr;
1891 gboolean is_fullscreen;
1892 GtkAction *fs_toggle_action;
1895 mgr = modest_runtime_get_window_mgr ();
1896 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1898 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1900 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1901 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1902 if (is_fullscreen != active) {
1903 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1912 set_homogeneous (GtkWidget *widget,
1915 if (GTK_IS_TOOL_ITEM (widget)) {
1916 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1917 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1922 modest_msg_view_window_show_toolbar (ModestWindow *self,
1923 gboolean show_toolbar)
1925 ModestMsgViewWindowPrivate *priv = NULL;
1926 ModestWindowPrivate *parent_priv;
1927 GtkWidget *reply_button = NULL, *menu = NULL;
1928 GtkWidget *placeholder = NULL;
1930 const gchar *action_name;
1933 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1934 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1936 /* Set optimized view status */
1937 priv->optimized_view = !show_toolbar;
1939 if (!parent_priv->toolbar) {
1940 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1942 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1944 /* Set homogeneous toolbar */
1945 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1946 set_homogeneous, NULL);
1948 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1949 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1950 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1951 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1952 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1953 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1954 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1955 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1957 /* Add ProgressBar (Transfer toolbar) */
1958 priv->progress_bar = modest_progress_bar_widget_new ();
1959 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1960 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1961 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1962 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1963 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1965 /* Connect cancel 'clicked' signal to abort progress mode */
1966 g_signal_connect(priv->cancel_toolitem, "clicked",
1967 G_CALLBACK(cancel_progressbar),
1970 /* Add it to the observers list */
1971 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1974 hildon_window_add_toolbar (HILDON_WINDOW (self),
1975 GTK_TOOLBAR (parent_priv->toolbar));
1978 /* Set reply button tap and hold menu */
1979 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1980 "/ToolBar/ToolbarMessageReply");
1981 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1982 "/ToolbarReplyCSM");
1983 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1987 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1988 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1989 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1991 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1992 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1995 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1996 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1999 /* Update also the actions (to update the toggles in the
2000 menus), we have to do it manually because some other window
2001 of the same time could have changed it (remember that the
2002 toolbar fullscreen mode is shared by all the windows of the
2004 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2005 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2007 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2009 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2010 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2015 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2017 ModestMsgViewWindow *window)
2019 if (!GTK_WIDGET_VISIBLE (window))
2022 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2026 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2028 ModestMsgViewWindowPrivate *priv;
2030 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2031 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2033 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2037 cancel_progressbar (GtkToolButton *toolbutton,
2038 ModestMsgViewWindow *self)
2041 ModestMsgViewWindowPrivate *priv;
2043 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2045 /* Get operation observers and cancel its current operation */
2046 tmp = priv->progress_widgets;
2048 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2049 tmp=g_slist_next(tmp);
2053 observers_empty (ModestMsgViewWindow *self)
2056 ModestMsgViewWindowPrivate *priv;
2057 gboolean is_empty = TRUE;
2058 guint pending_ops = 0;
2060 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2061 tmp = priv->progress_widgets;
2063 /* Check all observers */
2064 while (tmp && is_empty) {
2065 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2066 is_empty = pending_ops == 0;
2068 tmp = g_slist_next(tmp);
2075 on_account_removed (TnyAccountStore *account_store,
2076 TnyAccount *account,
2079 /* Do nothing if it's a transport account, because we only
2080 show the messages of a store account */
2081 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2082 const gchar *parent_acc = NULL;
2083 const gchar *our_acc = NULL;
2085 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2086 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2088 /* Close this window if I'm showing a message of the removed account */
2089 if (strcmp (parent_acc, our_acc) == 0)
2090 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2095 on_queue_changed (ModestMailOperationQueue *queue,
2096 ModestMailOperation *mail_op,
2097 ModestMailOperationQueueNotification type,
2098 ModestMsgViewWindow *self)
2101 ModestMsgViewWindowPrivate *priv;
2102 ModestMailOperationTypeOperation op_type;
2103 ModestToolBarModes mode;
2105 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2106 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2108 /* If this operations was created by another window, do nothing */
2109 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2112 /* Get toolbar mode from operation id*/
2113 op_type = modest_mail_operation_get_type_operation (mail_op);
2115 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2116 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2117 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2118 mode = TOOLBAR_MODE_TRANSFER;
2121 mode = TOOLBAR_MODE_NORMAL;
2125 /* Add operation observers and change toolbar if neccessary*/
2126 tmp = priv->progress_widgets;
2128 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2129 if (mode == TOOLBAR_MODE_TRANSFER) {
2130 /* Enable transfer toolbar mode */
2131 set_toolbar_transfer_mode(self);
2133 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2135 tmp = g_slist_next (tmp);
2140 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2141 if (mode == TOOLBAR_MODE_TRANSFER) {
2143 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2145 tmp = g_slist_next (tmp);
2149 /* If no more operations are being observed, NORMAL mode is enabled again */
2150 if (observers_empty (self)) {
2151 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2159 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2161 ModestMsgViewWindowPrivate *priv;
2162 GList *selected_attachments = NULL;
2164 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2165 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2167 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2169 return selected_attachments;
2173 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2175 ModestMsgViewWindowPrivate *priv;
2176 const gchar *msg_uid;
2177 gchar *attachment_uid = NULL;
2178 gint attachment_index = 0;
2181 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2182 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2183 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2185 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2186 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2187 attachment_index = g_list_index (attachments, mime_part);
2188 g_list_free (attachments);
2190 if (msg_uid && attachment_index >= 0) {
2191 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2194 if (mime_part == NULL) {
2195 gboolean error = FALSE;
2196 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2197 if (selected_attachments == NULL) {
2199 } else if (g_list_length (selected_attachments) > 1) {
2200 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2203 mime_part = (TnyMimePart *) selected_attachments->data;
2204 g_object_ref (mime_part);
2206 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2207 g_list_free (selected_attachments);
2212 g_object_ref (mime_part);
2215 if (tny_mime_part_is_purged (mime_part)) {
2216 g_object_unref (mime_part);
2220 if (!TNY_IS_MSG (mime_part)) {
2221 gchar *filepath = NULL;
2222 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2223 TnyFsStream *temp_stream = NULL;
2224 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2227 const gchar *content_type;
2228 content_type = tny_mime_part_get_content_type (mime_part);
2229 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2231 modest_platform_activate_file (filepath, content_type);
2232 g_object_unref (temp_stream);
2234 /* NOTE: files in the temporary area will be automatically
2235 * cleaned after some time if they are no longer in use */
2238 /* message attachment */
2239 TnyHeader *header = NULL;
2240 ModestWindowMgr *mgr;
2241 ModestWindow *msg_win = NULL;
2244 header = tny_msg_get_header (TNY_MSG (mime_part));
2245 mgr = modest_runtime_get_window_mgr ();
2246 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2249 if (msg_win) /* there is already a window for this uid; top it */
2250 gtk_window_present (GTK_WINDOW(msg_win));
2252 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2253 * thus, we don't do anything */
2254 g_warning ("window for is already being created");
2256 /* it's not found, so create a new window for it */
2257 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2258 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2260 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2261 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2262 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2263 modest_window_get_zoom (MODEST_WINDOW (window)));
2264 modest_window_mgr_register_window (mgr, msg_win);
2265 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2266 gtk_widget_show_all (GTK_WIDGET (msg_win));
2269 g_object_unref (mime_part);
2285 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2286 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2287 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2288 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2291 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2295 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2296 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2297 g_free (pair->filename);
2298 g_object_unref (pair->part);
2299 g_slice_free (SaveMimePartPair, pair);
2301 g_list_free (info->pairs);
2304 gtk_widget_destroy (info->banner);
2305 g_object_unref (info->banner);
2306 g_slice_free (SaveMimePartInfo, info);
2311 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2313 if (info->pairs != NULL) {
2314 save_mime_part_to_file (info);
2317 result = info->result;
2319 /* This is a GDK lock because we are an idle callback and
2320 * hildon_banner_show_information is or does Gtk+ code */
2322 gdk_threads_enter (); /* CHECKED */
2323 save_mime_part_info_free (info, TRUE);
2325 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2327 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2329 gdk_threads_leave (); /* CHECKED */
2336 save_mime_part_to_file (SaveMimePartInfo *info)
2338 GnomeVFSResult result;
2339 GnomeVFSHandle *handle;
2341 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2343 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0444);
2344 if (result == GNOME_VFS_OK) {
2345 stream = tny_vfs_stream_new (handle);
2346 tny_mime_part_decode_to_stream (pair->part, stream);
2347 g_object_unref (G_OBJECT (stream));
2348 g_object_unref (pair->part);
2349 g_slice_free (SaveMimePartPair, pair);
2350 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2351 info->result = TRUE;
2353 save_mime_part_info_free (info, FALSE);
2354 info->result = FALSE;
2357 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2362 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2364 gboolean is_ok = TRUE;
2365 gint replaced_files = 0;
2366 const GList *files = info->pairs;
2369 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2370 SaveMimePartPair *pair = iter->data;
2371 if (modest_maemo_utils_file_exists (pair->filename)) {
2375 if (replaced_files) {
2376 GtkWidget *confirm_overwrite_dialog;
2377 const gchar *message = (replaced_files == 1) ?
2378 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2379 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2380 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2383 gtk_widget_destroy (confirm_overwrite_dialog);
2387 save_mime_part_info_free (info, TRUE);
2389 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2390 _CS("sfil_ib_saving"));
2391 info->banner = g_object_ref (banner);
2392 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2393 g_object_unref (banner);
2400 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2402 gboolean clean_list = FALSE;
2403 ModestMsgViewWindowPrivate *priv;
2404 GList *files_to_save = NULL;
2405 GtkWidget *save_dialog = NULL;
2406 gchar *folder = NULL;
2407 gboolean canceled = FALSE;
2408 const gchar *filename = NULL;
2409 gchar *save_multiple_str = NULL;
2411 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2412 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2414 if (mime_parts == NULL) {
2415 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2416 if (mime_parts == NULL)
2421 /* prepare dialog */
2422 if (mime_parts->next == NULL) {
2423 /* only one attachment selected */
2424 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2425 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2426 filename = tny_mime_part_get_filename (mime_part);
2428 g_warning ("Tried to save a non-file attachment");
2432 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2433 g_list_length (mime_parts));
2436 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2437 GTK_FILE_CHOOSER_ACTION_SAVE);
2440 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2441 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2445 if (filename != NULL)
2446 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2449 /* if multiple, set multiple string */
2450 if (save_multiple_str) {
2451 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2455 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2456 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2458 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2459 hildon_banner_show_information
2460 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2464 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2465 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2467 if (tny_mime_part_is_attachment (mime_part)) {
2468 SaveMimePartPair *pair;
2470 if ((mime_parts->next != NULL) &&
2471 (tny_mime_part_get_filename (mime_part) == NULL))
2474 pair = g_slice_new0 (SaveMimePartPair);
2475 if (mime_parts->next == NULL) {
2476 pair->filename = g_strdup (chooser_uri);
2479 g_build_filename (chooser_uri,
2480 tny_mime_part_get_filename (mime_part), NULL);
2482 pair->part = g_object_ref (mime_part);
2483 files_to_save = g_list_prepend (files_to_save, pair);
2487 g_free (chooser_uri);
2490 gtk_widget_destroy (save_dialog);
2493 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2494 g_list_free (mime_parts);
2497 if (files_to_save != NULL) {
2498 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2499 info->pairs = files_to_save;
2500 info->result = TRUE;
2501 save_mime_parts_to_file_with_checks (info);
2506 show_remove_attachment_information (gpointer userdata)
2508 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2509 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2511 if (priv->remove_attachment_banner != NULL) {
2512 gtk_widget_destroy (priv->remove_attachment_banner);
2513 g_object_unref (priv->remove_attachment_banner);
2516 priv->remove_attachment_banner = g_object_ref (
2517 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2523 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2525 ModestMsgViewWindowPrivate *priv;
2526 GList *mime_parts = NULL, *node;
2527 gchar *confirmation_message;
2531 /* TnyFolder *folder; */
2533 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2534 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2537 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2539 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2541 /* Remove already purged messages from mime parts list */
2543 while (node != NULL) {
2544 TnyMimePart *part = TNY_MIME_PART (node->data);
2545 if (tny_mime_part_is_purged (part)) {
2546 GList *deleted_node = node;
2547 node = g_list_next (node);
2548 g_object_unref (part);
2549 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2551 node = g_list_next (node);
2555 if (mime_parts == NULL)
2558 n_attachments = g_list_length (mime_parts);
2559 if (n_attachments == 1) {
2560 const gchar *filename;
2562 if (TNY_IS_MSG (mime_parts->data)) {
2564 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2565 filename = tny_header_get_subject (header);
2566 g_object_unref (header);
2567 if (filename == NULL)
2568 filename = _("mail_va_no_subject");
2570 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2572 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2574 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2575 "mcen_nc_purge_files_text",
2576 n_attachments), n_attachments);
2578 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2579 confirmation_message);
2580 g_free (confirmation_message);
2582 if (response != GTK_RESPONSE_OK)
2585 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2586 /* folder = tny_msg_get_folder (msg); */
2587 /* tny_msg_uncache_attachments (msg); */
2588 /* tny_folder_refresh (folder, NULL); */
2589 /* g_object_unref (folder); */
2591 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2592 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2593 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2596 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2597 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2598 tny_msg_rewrite_cache (msg);
2599 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2601 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2602 g_list_free (mime_parts);
2604 if (priv->purge_timeout > 0) {
2605 g_source_remove (priv->purge_timeout);
2606 priv->purge_timeout = 0;
2609 if (priv->remove_attachment_banner) {
2610 gtk_widget_destroy (priv->remove_attachment_banner);
2611 g_object_unref (priv->remove_attachment_banner);
2612 priv->remove_attachment_banner = NULL;
2620 update_window_title (ModestMsgViewWindow *window)
2622 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2624 TnyHeader *header = NULL;
2625 const gchar *subject = NULL;
2627 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2630 header = tny_msg_get_header (msg);
2631 subject = tny_header_get_subject (header);
2632 g_object_unref (msg);
2635 if ((subject == NULL)||(subject[0] == '\0'))
2636 subject = _("mail_va_no_subject");
2638 gtk_window_set_title (GTK_WINDOW (window), subject);
2642 static void on_move_focus (ModestMsgViewWindow *window,
2643 GtkDirectionType direction,
2646 GtkWidget *current_focus = NULL;
2648 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2649 if ((current_focus != NULL) &&
2650 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2651 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");