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;
352 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
354 ModestMsgViewWindowPrivate *priv = NULL;
356 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
358 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
360 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
362 if (priv->progress_bar_timeout > 0) {
363 g_source_remove (priv->progress_bar_timeout);
364 priv->progress_bar_timeout = 0;
371 set_toolbar_mode (ModestMsgViewWindow *self,
372 ModestToolBarModes mode)
374 ModestWindowPrivate *parent_priv;
375 ModestMsgViewWindowPrivate *priv;
376 /* GtkWidget *widget = NULL; */
378 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
380 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
381 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
383 /* Sets current toolbar mode */
384 priv->current_toolbar_mode = mode;
386 /* Update toolbar dimming state */
387 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
390 case TOOLBAR_MODE_NORMAL:
391 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
392 /* gtk_action_set_sensitive (widget, TRUE); */
393 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
394 /* gtk_action_set_sensitive (widget, TRUE); */
395 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
396 /* gtk_action_set_sensitive (widget, TRUE); */
397 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
398 /* gtk_action_set_sensitive (widget, TRUE); */
400 if (priv->prev_toolitem)
401 gtk_widget_show (priv->prev_toolitem);
403 if (priv->next_toolitem)
404 gtk_widget_show (priv->next_toolitem);
406 if (priv->progress_toolitem)
407 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
408 if (priv->progress_bar)
409 gtk_widget_hide (priv->progress_bar);
411 if (priv->cancel_toolitem)
412 gtk_widget_hide (priv->cancel_toolitem);
414 /* Hide toolbar if optimized view is enabled */
415 if (priv->optimized_view) {
416 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
417 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
421 case TOOLBAR_MODE_TRANSFER:
422 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
423 /* gtk_action_set_sensitive (widget, FALSE); */
424 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
425 /* gtk_action_set_sensitive (widget, FALSE); */
426 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
427 /* gtk_action_set_sensitive (widget, FALSE); */
428 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
429 /* gtk_action_set_sensitive (widget, FALSE); */
431 if (priv->prev_toolitem)
432 gtk_widget_hide (priv->prev_toolitem);
434 if (priv->next_toolitem)
435 gtk_widget_hide (priv->next_toolitem);
437 if (priv->progress_toolitem)
438 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
439 if (priv->progress_bar)
440 gtk_widget_show (priv->progress_bar);
442 if (priv->cancel_toolitem)
443 gtk_widget_show (priv->cancel_toolitem);
445 /* Show toolbar if it's hiden (optimized view ) */
446 if (priv->optimized_view) {
447 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
448 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
453 g_return_if_reached ();
460 menubar_to_menu (GtkUIManager *ui_manager)
462 GtkWidget *main_menu;
464 GList *iter, *children;
466 /* Create new main menu */
467 main_menu = gtk_menu_new();
469 /* Get the menubar from the UI manager */
470 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
472 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
476 menu = GTK_WIDGET (iter->data);
477 gtk_widget_reparent(menu, main_menu);
479 iter = g_list_next (iter);
481 g_list_free (children);
487 init_window (ModestMsgViewWindow *obj)
489 GtkWidget *main_vbox;
490 ModestMsgViewWindowPrivate *priv;
491 ModestWindowPrivate *parent_priv;
493 GtkAction *action = NULL;
495 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
496 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
498 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
499 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
500 main_vbox = gtk_vbox_new (FALSE, 6);
503 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
504 conf = modest_runtime_get_conf ();
505 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
506 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
507 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
508 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
509 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
510 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
511 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
512 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
513 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
514 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
516 #ifdef MODEST_USE_MOZEMBED
517 priv->main_scroll = priv->msg_view;
518 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
520 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
521 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
523 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
524 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
525 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
527 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
528 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
530 priv->find_toolbar = hildon_find_toolbar_new (NULL);
531 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
532 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
533 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
534 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
536 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);
537 gtk_widget_show_all (GTK_WIDGET(main_vbox));
541 modest_msg_view_window_disconnect_signals (ModestWindow *self)
543 ModestMsgViewWindowPrivate *priv;
544 ModestHeaderView *header_view = NULL;
545 ModestMainWindow *main_window = NULL;
546 ModestWindowMgr *window_mgr = NULL;
548 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
550 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
551 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
552 priv->clipboard_change_handler))
553 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
554 priv->clipboard_change_handler);
556 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
557 priv->queue_change_handler))
558 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
559 priv->queue_change_handler);
561 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
562 priv->account_removed_handler))
563 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
564 priv->account_removed_handler);
566 if (priv->header_model) {
567 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
568 priv->row_changed_handler))
569 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
570 priv->row_changed_handler);
572 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
573 priv->row_deleted_handler))
574 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
575 priv->row_deleted_handler);
577 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
578 priv->row_inserted_handler))
579 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
580 priv->row_inserted_handler);
582 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
583 priv->rows_reordered_handler))
584 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
585 priv->rows_reordered_handler);
588 window_mgr = modest_runtime_get_window_mgr();
589 g_assert(window_mgr != NULL);
591 main_window = MODEST_MAIN_WINDOW(
592 modest_window_mgr_get_main_window(window_mgr));
594 if(main_window == NULL)
597 header_view = MODEST_HEADER_VIEW(
598 modest_main_window_get_child_widget(
599 main_window, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
601 if (header_view == NULL)
604 modest_header_view_remove_observer(header_view,
605 MODEST_HEADER_VIEW_OBSERVER(self));
609 modest_msg_view_window_finalize (GObject *obj)
611 ModestMsgViewWindowPrivate *priv;
613 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
615 /* Sanity check: shouldn't be needed, the window mgr should
616 call this function before */
617 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
619 if (priv->header_model != NULL) {
620 g_object_unref (priv->header_model);
621 priv->header_model = NULL;
624 if (priv->progress_bar_timeout > 0) {
625 g_source_remove (priv->progress_bar_timeout);
626 priv->progress_bar_timeout = 0;
629 if (priv->remove_attachment_banner) {
630 gtk_widget_destroy (priv->remove_attachment_banner);
631 g_object_unref (priv->remove_attachment_banner);
632 priv->remove_attachment_banner = NULL;
635 if (priv->purge_timeout > 0) {
636 g_source_remove (priv->purge_timeout);
637 priv->purge_timeout = 0;
640 if (priv->row_reference) {
641 gtk_tree_row_reference_free (priv->row_reference);
642 priv->row_reference = NULL;
645 if (priv->next_row_reference) {
646 gtk_tree_row_reference_free (priv->next_row_reference);
647 priv->next_row_reference = NULL;
651 g_free (priv->msg_uid);
652 priv->msg_uid = NULL;
655 G_OBJECT_CLASS(parent_class)->finalize (obj);
659 select_next_valid_row (GtkTreeModel *model,
660 GtkTreeRowReference **row_reference,
663 GtkTreeIter tmp_iter;
664 GtkTreePath *path, *next;
665 gboolean retval = FALSE;
667 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
669 path = gtk_tree_row_reference_get_path (*row_reference);
670 gtk_tree_model_get_iter (model, &tmp_iter, path);
671 gtk_tree_row_reference_free (*row_reference);
672 *row_reference = NULL;
674 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
675 next = gtk_tree_model_get_path (model, &tmp_iter);
676 *row_reference = gtk_tree_row_reference_new (model, next);
678 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
679 next = gtk_tree_model_get_path (model, &tmp_iter);
681 /* Ensure that we are not selecting the same */
682 if (gtk_tree_path_compare (path, next) != 0) {
683 *row_reference = gtk_tree_row_reference_new (model, next);
689 gtk_tree_path_free (path);
694 /* TODO: This should be in _init(), with the parameters as properties. */
696 modest_msg_view_window_construct (ModestMsgViewWindow *self,
697 const gchar *modest_account_name,
698 const gchar *msg_uid)
701 ModestMsgViewWindowPrivate *priv = NULL;
702 ModestWindowPrivate *parent_priv = NULL;
703 ModestDimmingRulesGroup *menu_rules_group = NULL;
704 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
705 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
706 GtkActionGroup *action_group = NULL;
707 GError *error = NULL;
708 GdkPixbuf *window_icon;
710 obj = G_OBJECT (self);
711 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
712 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
714 priv->msg_uid = g_strdup (msg_uid);
716 parent_priv->ui_manager = gtk_ui_manager_new();
717 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
719 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
720 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
722 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
723 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
724 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
726 /* Add common actions */
727 gtk_action_group_add_actions (action_group,
728 modest_action_entries,
729 G_N_ELEMENTS (modest_action_entries),
731 gtk_action_group_add_toggle_actions (action_group,
732 modest_toggle_action_entries,
733 G_N_ELEMENTS (modest_toggle_action_entries),
735 gtk_action_group_add_toggle_actions (action_group,
736 msg_view_toggle_action_entries,
737 G_N_ELEMENTS (msg_view_toggle_action_entries),
739 gtk_action_group_add_radio_actions (action_group,
740 msg_view_zoom_action_entries,
741 G_N_ELEMENTS (msg_view_zoom_action_entries),
743 G_CALLBACK (modest_ui_actions_on_change_zoom),
746 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
747 g_object_unref (action_group);
749 /* Load the UI definition */
750 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
753 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
754 g_error_free (error);
759 /* Add common dimming rules */
760 modest_dimming_rules_group_add_rules (menu_rules_group,
761 modest_msg_view_menu_dimming_entries,
762 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
763 MODEST_WINDOW (self));
764 modest_dimming_rules_group_add_rules (toolbar_rules_group,
765 modest_msg_view_toolbar_dimming_entries,
766 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
767 MODEST_WINDOW (self));
768 modest_dimming_rules_group_add_rules (clipboard_rules_group,
769 modest_msg_view_clipboard_dimming_entries,
770 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
771 MODEST_WINDOW (self));
773 /* Insert dimming rules group for this window */
774 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
775 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
776 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
777 g_object_unref (menu_rules_group);
778 g_object_unref (toolbar_rules_group);
779 g_object_unref (clipboard_rules_group);
781 /* Add accelerators */
782 gtk_window_add_accel_group (GTK_WINDOW (obj),
783 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
786 init_window (MODEST_MSG_VIEW_WINDOW(obj));
787 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
789 /* Set window icon */
790 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
792 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
793 g_object_unref (window_icon);
796 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
798 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
799 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
800 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
801 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
802 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
803 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
804 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
805 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
806 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
807 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
809 g_signal_connect (G_OBJECT (obj), "key-release-event",
810 G_CALLBACK (modest_msg_view_window_key_release_event),
813 g_signal_connect (G_OBJECT (obj), "window-state-event",
814 G_CALLBACK (modest_msg_view_window_window_state_event),
817 g_signal_connect (G_OBJECT (obj), "move-focus",
818 G_CALLBACK (on_move_focus), obj);
820 /* Mail Operation Queue */
821 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
823 G_CALLBACK (on_queue_changed),
826 /* Account manager */
827 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
829 G_CALLBACK(on_account_removed),
832 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
834 priv->last_search = NULL;
836 /* Init the clipboard actions dim status */
837 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
839 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
841 /* Check toolbar dimming rules */
842 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
843 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
848 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
849 const gchar *modest_account_name,
850 const gchar *msg_uid,
852 GtkTreeRowReference *row_reference)
854 ModestMsgViewWindow *window = NULL;
855 ModestMsgViewWindowPrivate *priv = NULL;
856 TnyFolder *header_folder = NULL;
857 ModestHeaderView *header_view = NULL;
858 ModestMainWindow *main_window = NULL;
859 ModestWindowMgr *window_mgr = NULL;
861 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
862 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
863 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
865 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
867 /* Remember the message list's TreeModel so we can detect changes
868 * and change the list selection when necessary: */
869 window_mgr = modest_runtime_get_window_mgr();
870 g_assert(window_mgr != NULL);
871 main_window = MODEST_MAIN_WINDOW(
872 modest_window_mgr_get_main_window(window_mgr));
873 g_assert(main_window != NULL);
874 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
875 main_window, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
876 if (header_view != NULL){
877 header_folder = modest_header_view_get_folder(header_view);
878 g_assert(header_folder != NULL);
879 priv->header_folder_id = tny_folder_get_id(header_folder);
880 g_assert(priv->header_folder_id != NULL);
881 g_object_unref(header_folder);
884 priv->header_model = g_object_ref(model);
885 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
886 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
887 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
889 priv->row_changed_handler = g_signal_connect(
890 GTK_TREE_MODEL(model), "row-changed",
891 G_CALLBACK(modest_msg_view_window_on_row_changed),
893 priv->row_deleted_handler = g_signal_connect(
894 GTK_TREE_MODEL(model), "row-deleted",
895 G_CALLBACK(modest_msg_view_window_on_row_deleted),
897 priv->row_inserted_handler = g_signal_connect (
898 GTK_TREE_MODEL(model), "row-inserted",
899 G_CALLBACK(modest_msg_view_window_on_row_inserted),
901 priv->rows_reordered_handler = g_signal_connect(
902 GTK_TREE_MODEL(model), "rows-reordered",
903 G_CALLBACK(modest_msg_view_window_on_row_reordered),
906 if (header_view != NULL){
907 modest_header_view_add_observer(header_view,
908 MODEST_HEADER_VIEW_OBSERVER(window));
911 gtk_widget_show_all (GTK_WIDGET (window));
913 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
915 modest_msg_view_window_update_priority (window);
917 /* Check toolbar dimming rules */
918 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
920 return MODEST_WINDOW(window);
924 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
925 const gchar *modest_account_name,
926 const gchar *msg_uid)
928 ModestMsgViewWindow *window = NULL;
929 ModestMsgViewWindowPrivate *priv = NULL;
931 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
932 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
933 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
935 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
937 /* Remember that this is a search result,
938 * so we can disable some UI appropriately: */
939 priv->is_search_result = TRUE;
941 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
943 return MODEST_WINDOW(window);
947 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
948 const gchar *modest_account_name,
949 const gchar *msg_uid)
952 ModestMsgViewWindowPrivate *priv;
953 g_return_val_if_fail (msg, NULL);
955 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
956 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
957 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
958 modest_account_name, msg_uid);
960 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
962 return MODEST_WINDOW(obj);
965 void modest_msg_view_window_on_row_changed(
966 GtkTreeModel *header_model,
969 ModestMsgViewWindow *window){
970 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
973 void modest_msg_view_window_on_row_deleted(
974 GtkTreeModel *header_model,
976 ModestMsgViewWindow *window){
977 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
980 /* On insertions we check if the folder still has the message we are
981 * showing or do not. If do not, we do nothing. Which means we are still
982 * not attached to any header folder and thus next/prev buttons are
983 * still dimmed. Once the message that is shown by msg-view is found, the
984 * new model of header-view will be attached and the references will be set.
985 * On each further insertions dimming rules will be checked. However
986 * this requires extra CPU time at least works.
987 * (An message might be deleted from TnyFolder and thus will not be
988 * inserted into the model again for example if it is removed by the
989 * imap server and the header view is refreshed.)
991 void modest_msg_view_window_on_row_inserted(
992 GtkTreeModel *new_model,
993 GtkTreePath *tree_path,
994 GtkTreeIter *tree_iter,
995 ModestMsgViewWindow *window){
996 ModestMsgViewWindowPrivate *priv = NULL;
997 TnyHeader *header = NULL;
1000 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1002 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1004 /* If we already has a model attached then the message shown by
1005 * msg-view is in it, and thus we do not need any actions but
1006 * to check the dimming rules.*/
1007 if(priv->header_model != NULL){
1008 gtk_tree_row_reference_free(priv->next_row_reference);
1009 priv->next_row_reference = gtk_tree_row_reference_copy(
1010 priv->row_reference);
1011 select_next_valid_row (priv->header_model,
1012 &(priv->next_row_reference), FALSE);
1013 modest_ui_actions_check_toolbar_dimming_rules (
1014 MODEST_WINDOW (window));
1018 /* Check if the newly inserted message is the same we are actually
1019 * showing. IF not, we should remain detached from the header model
1020 * and thus prev and next toolbarbuttons should remain dimmed. */
1021 gtk_tree_model_get (new_model, tree_iter,
1022 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1023 uid = modest_tny_folder_get_header_unique_id(header);
1024 if(!g_str_equal(priv->msg_uid, uid)){
1030 /* Setup row_reference for the actual msg. */
1031 priv->row_reference = gtk_tree_row_reference_new(
1032 new_model, tree_path);
1033 if(priv->row_reference == NULL){
1034 g_warning("No reference for msg header item.");
1038 /* Attach new_model and connect some callback to it to become able
1039 * to detect changes in header-view. */
1040 priv->header_model = g_object_ref(new_model);
1041 g_signal_connect (new_model, "row-changed",
1042 G_CALLBACK (modest_msg_view_window_on_row_changed),
1044 g_signal_connect (new_model, "row-deleted",
1045 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1047 g_signal_connect (new_model, "rows-reordered",
1048 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1051 /* Now set up next_row_reference. */
1052 priv->next_row_reference = gtk_tree_row_reference_copy(
1053 priv->row_reference);
1054 select_next_valid_row (priv->header_model,
1055 &(priv->next_row_reference), FALSE);
1057 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1060 void modest_msg_view_window_on_row_reordered(
1061 GtkTreeModel *header_model,
1065 ModestMsgViewWindow *window){
1066 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1069 /* The modest_msg_view_window_update_model_replaced implements update
1070 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1071 * actually belongs to the header-view is the same as the TnyFolder of
1072 * the message of msg-view or not. If they are different, there is
1073 * nothing to do. If they are the same, then the model has replaced and
1074 * the reference in msg-view shall be replaced from the old model to
1075 * the new model. In this case the view will be detached from it's
1076 * header folder. From this point the next/prev buttons are dimmed.
1078 void modest_msg_view_window_update_model_replaced(
1079 ModestHeaderViewObserver *observer,
1080 GtkTreeModel *model,
1081 const gchar *tny_folder_id){
1082 ModestMsgViewWindowPrivate *priv = NULL;
1083 ModestMsgViewWindow *window = NULL;
1085 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1086 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1088 window = MODEST_MSG_VIEW_WINDOW(observer);
1089 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1091 /* If there is an other folder in the header-view then we do
1092 * not care about it's model (msg list). Else if the
1093 * header-view shows the folder the msg shown by us is in, we
1094 * shall replace our model reference and make some check. */
1095 if(tny_folder_id == NULL ||
1096 !g_str_equal(tny_folder_id, priv->header_folder_id))
1099 /* Model is changed(replaced), so we should forget the old
1100 * one. Because there might be other references and there
1101 * might be some change on the model even if we unreferenced
1102 * it, we need to disconnect our signals here. */
1103 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1104 priv->row_changed_handler))
1105 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1106 priv->row_changed_handler);
1107 priv->row_changed_handler = 0;
1108 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1109 priv->row_deleted_handler))
1110 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1111 priv->row_deleted_handler);
1112 priv->row_deleted_handler = 0;
1113 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1114 priv->row_inserted_handler))
1115 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1116 priv->row_inserted_handler);
1117 priv->row_inserted_handler = 0;
1118 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1119 priv->rows_reordered_handler))
1120 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1121 priv->rows_reordered_handler);
1122 priv->rows_reordered_handler = 0;
1123 g_object_unref(priv->header_model);
1124 priv->header_model = NULL;
1125 g_object_unref(priv->row_reference);
1126 priv->row_reference = NULL;
1127 g_object_unref(priv->next_row_reference);
1128 priv->next_row_reference = NULL;
1130 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1132 if(tny_folder_id == NULL)
1135 g_assert(model != NULL);
1137 /* Also we must connect to the new model for row insertions.
1138 * Only for insertions now. We will need other ones only after
1139 * the msg is show by msg-view is added to the new model. */
1140 priv->row_inserted_handler = g_signal_connect (
1141 model, "row-inserted",
1142 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1147 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1149 ModestMsgViewWindowPrivate *priv= NULL;
1151 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1152 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1154 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1158 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1160 ModestMsgViewWindowPrivate *priv= NULL;
1162 TnyHeader *header = NULL;
1163 GtkTreePath *path = NULL;
1166 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1167 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1169 /* If the message was not obtained from a treemodel,
1170 * for instance if it was opened directly by the search UI:
1172 if (priv->header_model == NULL) {
1173 msg = modest_msg_view_window_get_message (self);
1175 header = tny_msg_get_header (msg);
1176 g_object_unref (msg);
1181 /* Get iter of the currently selected message in the header view: */
1182 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1183 * instead of sometimes retrieving it from the header view?
1184 * Then we wouldn't be dependent on the message actually still being selected
1185 * in the header view. murrayc. */
1186 if (!gtk_tree_row_reference_valid (priv->row_reference))
1188 path = gtk_tree_row_reference_get_path (priv->row_reference);
1189 g_return_val_if_fail (path != NULL, NULL);
1190 gtk_tree_model_get_iter (priv->header_model,
1194 /* Get current message header */
1195 gtk_tree_model_get (priv->header_model, &iter,
1196 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1199 gtk_tree_path_free (path);
1204 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1206 ModestMsgView *msg_view;
1207 ModestMsgViewWindowPrivate *priv;
1209 g_return_val_if_fail (self, NULL);
1211 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1213 msg_view = MODEST_MSG_VIEW (priv->msg_view);
1215 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1219 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1221 ModestMsgViewWindowPrivate *priv;
1223 g_return_val_if_fail (self, NULL);
1225 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1227 return (const gchar*) priv->msg_uid;
1231 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1234 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1235 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1236 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1240 is_active = gtk_toggle_action_get_active (toggle);
1243 gtk_widget_show (priv->find_toolbar);
1244 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1246 gtk_widget_hide (priv->find_toolbar);
1249 /* update the toggle buttons status */
1250 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1251 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1252 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1253 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1258 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1259 ModestMsgViewWindow *obj)
1261 GtkToggleAction *toggle;
1262 ModestWindowPrivate *parent_priv;
1263 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1265 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1266 gtk_toggle_action_set_active (toggle, FALSE);
1270 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1271 ModestMsgViewWindow *obj)
1273 gchar *current_search;
1274 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1276 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1277 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1281 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1283 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1284 g_free (current_search);
1285 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1289 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1291 g_free (priv->last_search);
1292 priv->last_search = g_strdup (current_search);
1293 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1296 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1297 g_free (priv->last_search);
1298 priv->last_search = NULL;
1300 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1303 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1304 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1305 g_free (priv->last_search);
1306 priv->last_search = NULL;
1308 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1312 g_free (current_search);
1317 modest_msg_view_window_set_zoom (ModestWindow *window,
1320 ModestMsgViewWindowPrivate *priv;
1321 ModestWindowPrivate *parent_priv;
1322 GtkAction *action = NULL;
1323 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1325 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1327 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1328 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1329 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1331 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1332 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1334 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1338 modest_msg_view_window_get_zoom (ModestWindow *window)
1340 ModestMsgViewWindowPrivate *priv;
1342 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1344 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1345 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1349 modest_msg_view_window_zoom_plus (ModestWindow *window)
1351 ModestWindowPrivate *parent_priv;
1352 GtkRadioAction *zoom_radio_action;
1353 GSList *group, *node;
1355 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1356 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1357 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1359 group = gtk_radio_action_get_group (zoom_radio_action);
1361 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1362 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1366 for (node = group; node != NULL; node = g_slist_next (node)) {
1367 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1368 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1376 modest_msg_view_window_zoom_minus (ModestWindow *window)
1378 ModestWindowPrivate *parent_priv;
1379 GtkRadioAction *zoom_radio_action;
1380 GSList *group, *node;
1382 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1383 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1384 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1386 group = gtk_radio_action_get_group (zoom_radio_action);
1388 for (node = group; node != NULL; node = g_slist_next (node)) {
1389 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1390 if (node->next != NULL) {
1391 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1394 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1404 modest_msg_view_window_key_release_event (GtkWidget *window,
1408 if (event->type == GDK_KEY_RELEASE) {
1409 switch (event->keyval) {
1411 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1415 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1428 modest_msg_view_window_scroll_up (ModestWindow *window)
1430 ModestMsgViewWindowPrivate *priv;
1431 gboolean return_value;
1433 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1434 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1438 modest_msg_view_window_scroll_down (ModestWindow *window)
1440 ModestMsgViewWindowPrivate *priv;
1441 gboolean return_value;
1443 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1444 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1448 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1451 ModestMsgViewWindowPrivate *priv;
1452 GtkTreeIter tmp_iter;
1453 gboolean is_last_selected;
1455 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1456 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1458 /*if no model (so no rows at all), then virtually we are the last*/
1459 if (!priv->header_model)
1462 path = gtk_tree_row_reference_get_path (priv->row_reference);
1466 is_last_selected = TRUE;
1467 while (is_last_selected) {
1469 gtk_tree_path_next (path);
1470 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1472 gtk_tree_model_get (priv->header_model, &tmp_iter,
1473 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1475 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1476 is_last_selected = FALSE;
1478 gtk_tree_path_free (path);
1479 return is_last_selected;
1483 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1485 ModestMsgViewWindowPrivate *priv;
1487 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1488 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1490 return priv->header_model != NULL;
1494 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1496 ModestMsgViewWindowPrivate *priv;
1498 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1499 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1501 return priv->is_search_result;
1505 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1508 ModestMsgViewWindowPrivate *priv;
1509 gboolean is_first_selected;
1510 GtkTreeIter tmp_iter;
1511 /* gchar * path_string;*/
1513 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1514 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1516 /*if no model (so no rows at all), then virtually we are the first*/
1517 if (!priv->header_model)
1520 path = gtk_tree_row_reference_get_path (priv->row_reference);
1524 /* path_string = gtk_tree_path_to_string (path);
1525 is_first_selected = strcmp (path_string, "0");
1527 g_free (path_string);
1528 gtk_tree_path_free (path);
1530 return is_first_selected;*/
1532 is_first_selected = TRUE;
1533 while (is_first_selected) {
1535 if(!gtk_tree_path_prev (path))
1537 /* Here the 'if' is needless for logic, but let make sure
1538 * iter is valid for gtk_tree_model_get. */
1539 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1541 gtk_tree_model_get (priv->header_model, &tmp_iter,
1542 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1544 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1545 is_first_selected = FALSE;
1547 gtk_tree_path_free (path);
1548 return is_first_selected;
1552 * Reads the message whose summary item is @header. It takes care of
1553 * several things, among others:
1555 * If the message was not previously downloaded then ask the user
1556 * before downloading. If there is no connection launch the connection
1557 * dialog. Update toolbar dimming rules.
1559 * Returns: TRUE if the mail operation was started, otherwise if the
1560 * user do not want to download the message, or if the user do not
1561 * want to connect, then the operation is not issued
1564 message_reader (ModestMsgViewWindow *window,
1565 ModestMsgViewWindowPrivate *priv,
1567 GtkTreeRowReference *row_reference)
1569 ModestMailOperation *mail_op = NULL;
1570 ModestMailOperationTypeOperation op_type;
1571 gboolean already_showing = FALSE;
1572 ModestWindow *msg_window = NULL;
1573 ModestWindowMgr *mgr;
1575 g_return_val_if_fail (row_reference != NULL, FALSE);
1577 mgr = modest_runtime_get_window_mgr ();
1578 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1579 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1582 gtk_window_present (GTK_WINDOW (msg_window));
1583 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1587 /* Msg download completed */
1588 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1589 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1591 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1593 /* Ask the user if he wants to download the message if
1595 if (!tny_device_is_online (modest_runtime_get_device())) {
1596 TnyFolder *folder = NULL;
1597 GtkResponseType response;
1599 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1600 _("mcen_nc_get_msg"));
1601 if (response == GTK_RESPONSE_CANCEL)
1604 /* Offer the connection dialog if necessary */
1605 folder = tny_header_get_folder (header);
1607 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1608 TNY_FOLDER_STORE (folder))) {
1609 g_object_unref (folder);
1612 g_object_unref (folder);
1617 /* New mail operation */
1618 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1619 modest_ui_actions_get_msgs_full_error_handler,
1622 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1623 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1624 g_object_unref (mail_op);
1626 /* Update toolbar dimming rules */
1627 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1633 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1635 ModestMsgViewWindowPrivate *priv;
1636 GtkTreePath *path= NULL;
1637 GtkTreeIter tmp_iter;
1639 gboolean retval = TRUE;
1640 GtkTreeRowReference *row_reference = NULL;
1642 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1643 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1645 /* Update the next row reference if it's not valid. This could
1646 happen if for example the header which it was pointing to,
1647 was deleted. The best place to do it is in the row-deleted
1648 handler but the tinymail model do not work like the glib
1649 tree models and reports the deletion when the row is still
1651 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1652 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1653 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1654 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1657 if (priv->next_row_reference)
1658 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1662 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1664 gtk_tree_model_get_iter (priv->header_model,
1667 gtk_tree_path_free (path);
1669 gtk_tree_model_get (priv->header_model, &tmp_iter,
1670 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1673 /* Read the message & show it */
1674 if (!message_reader (window, priv, header, row_reference)) {
1676 gtk_tree_row_reference_free (row_reference);
1680 g_object_unref (header);
1686 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1688 ModestMsgViewWindowPrivate *priv = NULL;
1689 TnyHeader *header = NULL;
1691 GtkTreePath *path = NULL;
1692 GtkTreeRowReference *row_reference = NULL;
1694 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1695 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1697 /* Check that the model is not empty */
1698 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1701 /* Get the header */
1702 gtk_tree_model_get (priv->header_model,
1704 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1706 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1707 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1708 g_object_unref (header);
1709 return modest_msg_view_window_select_next_message (self);
1712 path = gtk_tree_model_get_path (priv->header_model, &iter);
1713 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1714 gtk_tree_path_free (path);
1716 /* Read the message & show it */
1717 message_reader (self, priv, header, row_reference);
1720 g_object_unref (header);
1726 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1728 ModestMsgViewWindowPrivate *priv = NULL;
1730 GtkTreeRowReference *row_reference = NULL;
1732 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1733 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1735 /* Return inmediatly if there is no header model */
1736 if (!priv->header_model)
1739 path = gtk_tree_row_reference_get_path (priv->row_reference);
1740 while (gtk_tree_path_prev (path)) {
1744 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1745 gtk_tree_model_get (priv->header_model, &iter,
1746 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1750 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1751 g_object_unref (header);
1755 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1756 /* Read the message & show it */
1757 if (!message_reader (window, priv, header, row_reference)) {
1758 gtk_tree_row_reference_free (row_reference);
1759 g_object_unref (header);
1763 gtk_tree_path_free (path);
1764 g_object_unref (header);
1769 gtk_tree_path_free (path);
1774 view_msg_cb (ModestMailOperation *mail_op,
1779 ModestMsgViewWindow *self = NULL;
1780 ModestMsgViewWindowPrivate *priv = NULL;
1781 GtkTreeRowReference *row_reference = NULL;
1783 /* If there was any error */
1784 row_reference = (GtkTreeRowReference *) user_data;
1785 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1786 gtk_tree_row_reference_free (row_reference);
1790 /* Get the window */
1791 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1792 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1793 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1795 /* Update the row reference */
1796 gtk_tree_row_reference_free (priv->row_reference);
1797 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1798 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1799 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1800 gtk_tree_row_reference_free (row_reference);
1802 /* Mark header as read */
1803 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1804 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
1806 /* Set new message */
1807 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1808 modest_msg_view_window_update_priority (self);
1809 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1810 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1812 /* Set the new message uid of the window */
1813 if (priv->msg_uid) {
1814 g_free (priv->msg_uid);
1815 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1818 /* Notify the observers */
1819 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1820 0, priv->header_model, priv->row_reference);
1822 /* Free new references */
1823 g_object_unref (self);
1827 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1829 ModestMsgViewWindowPrivate *priv;
1831 TnyFolderType folder_type;
1833 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1835 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1837 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1841 folder = tny_msg_get_folder (msg);
1843 folder_type = tny_folder_get_folder_type (folder);
1844 g_object_unref (folder);
1846 g_object_unref (msg);
1854 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1856 ModestMsgViewWindowPrivate *priv;
1857 TnyHeaderFlags flags = 0;
1859 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1861 if (priv->header_model) {
1864 GtkTreePath *path = NULL;
1866 path = gtk_tree_row_reference_get_path (priv->row_reference);
1867 g_return_if_fail (path != NULL);
1868 gtk_tree_model_get_iter (priv->header_model,
1870 gtk_tree_row_reference_get_path (priv->row_reference));
1872 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1874 flags = tny_header_get_flags (header);
1875 gtk_tree_path_free (path);
1878 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1883 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1885 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1886 ModestWindowPrivate *parent_priv;
1887 ModestWindowMgr *mgr;
1888 gboolean is_fullscreen;
1889 GtkAction *fs_toggle_action;
1892 mgr = modest_runtime_get_window_mgr ();
1893 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1895 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1897 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1898 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1899 if (is_fullscreen != active) {
1900 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1909 set_homogeneous (GtkWidget *widget,
1912 if (GTK_IS_TOOL_ITEM (widget)) {
1913 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1914 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1919 modest_msg_view_window_show_toolbar (ModestWindow *self,
1920 gboolean show_toolbar)
1922 ModestMsgViewWindowPrivate *priv = NULL;
1923 ModestWindowPrivate *parent_priv;
1924 GtkWidget *reply_button = NULL, *menu = NULL;
1925 GtkWidget *placeholder = NULL;
1927 const gchar *action_name;
1930 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1931 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1933 /* Set optimized view status */
1934 priv->optimized_view = !show_toolbar;
1936 if (!parent_priv->toolbar) {
1937 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1939 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1941 /* Set homogeneous toolbar */
1942 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1943 set_homogeneous, NULL);
1945 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1946 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1947 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1948 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1949 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1950 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1951 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1952 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1954 /* Add ProgressBar (Transfer toolbar) */
1955 priv->progress_bar = modest_progress_bar_widget_new ();
1956 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1957 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1958 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1959 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1960 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1962 /* Connect cancel 'clicked' signal to abort progress mode */
1963 g_signal_connect(priv->cancel_toolitem, "clicked",
1964 G_CALLBACK(cancel_progressbar),
1967 /* Add it to the observers list */
1968 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1971 hildon_window_add_toolbar (HILDON_WINDOW (self),
1972 GTK_TOOLBAR (parent_priv->toolbar));
1975 /* Set reply button tap and hold menu */
1976 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1977 "/ToolBar/ToolbarMessageReply");
1978 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1979 "/ToolbarReplyCSM");
1980 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1984 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1985 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1986 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1988 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1989 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1992 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1993 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1996 /* Update also the actions (to update the toggles in the
1997 menus), we have to do it manually because some other window
1998 of the same time could have changed it (remember that the
1999 toolbar fullscreen mode is shared by all the windows of the
2001 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2002 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2004 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2006 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2007 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2012 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2014 ModestMsgViewWindow *window)
2016 if (!GTK_WIDGET_VISIBLE (window))
2019 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2023 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2025 ModestMsgViewWindowPrivate *priv;
2027 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2028 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2030 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2034 cancel_progressbar (GtkToolButton *toolbutton,
2035 ModestMsgViewWindow *self)
2038 ModestMsgViewWindowPrivate *priv;
2040 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2042 /* Get operation observers and cancel its current operation */
2043 tmp = priv->progress_widgets;
2045 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2046 tmp=g_slist_next(tmp);
2050 observers_empty (ModestMsgViewWindow *self)
2053 ModestMsgViewWindowPrivate *priv;
2054 gboolean is_empty = TRUE;
2055 guint pending_ops = 0;
2057 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2058 tmp = priv->progress_widgets;
2060 /* Check all observers */
2061 while (tmp && is_empty) {
2062 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2063 is_empty = pending_ops == 0;
2065 tmp = g_slist_next(tmp);
2072 on_account_removed (TnyAccountStore *account_store,
2073 TnyAccount *account,
2076 /* Do nothing if it's a transport account, because we only
2077 show the messages of a store account */
2078 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2079 const gchar *parent_acc = NULL;
2080 const gchar *our_acc = NULL;
2082 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2083 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2085 /* Close this window if I'm showing a message of the removed account */
2086 if (strcmp (parent_acc, our_acc) == 0)
2087 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2092 on_queue_changed (ModestMailOperationQueue *queue,
2093 ModestMailOperation *mail_op,
2094 ModestMailOperationQueueNotification type,
2095 ModestMsgViewWindow *self)
2098 ModestMsgViewWindowPrivate *priv;
2099 ModestMailOperationTypeOperation op_type;
2100 ModestToolBarModes mode;
2102 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2103 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2105 /* If this operations was created by another window, do nothing */
2106 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2109 /* Get toolbar mode from operation id*/
2110 op_type = modest_mail_operation_get_type_operation (mail_op);
2112 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2113 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2114 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2115 mode = TOOLBAR_MODE_TRANSFER;
2118 mode = TOOLBAR_MODE_NORMAL;
2122 /* Add operation observers and change toolbar if neccessary*/
2123 tmp = priv->progress_widgets;
2125 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2126 if (mode == TOOLBAR_MODE_TRANSFER) {
2127 /* Enable transfer toolbar mode */
2128 set_toolbar_transfer_mode(self);
2130 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2132 tmp = g_slist_next (tmp);
2137 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2138 if (mode == TOOLBAR_MODE_TRANSFER) {
2140 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2142 tmp = g_slist_next (tmp);
2146 /* If no more operations are being observed, NORMAL mode is enabled again */
2147 if (observers_empty (self)) {
2148 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2156 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2158 ModestMsgViewWindowPrivate *priv;
2159 GList *selected_attachments = NULL;
2161 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2162 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2164 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2166 return selected_attachments;
2170 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2172 ModestMsgViewWindowPrivate *priv;
2173 const gchar *msg_uid;
2174 gchar *attachment_uid = NULL;
2175 gint attachment_index = 0;
2178 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2179 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2180 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2182 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2183 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2184 attachment_index = g_list_index (attachments, mime_part);
2185 g_list_free (attachments);
2187 if (msg_uid && attachment_index >= 0) {
2188 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2191 if (mime_part == NULL) {
2192 gboolean error = FALSE;
2193 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2194 if (selected_attachments == NULL) {
2196 } else if (g_list_length (selected_attachments) > 1) {
2197 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2200 mime_part = (TnyMimePart *) selected_attachments->data;
2201 g_object_ref (mime_part);
2203 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2204 g_list_free (selected_attachments);
2209 g_object_ref (mime_part);
2212 if (tny_mime_part_is_purged (mime_part)) {
2213 g_object_unref (mime_part);
2217 if (!TNY_IS_MSG (mime_part)) {
2218 gchar *filepath = NULL;
2219 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2220 TnyFsStream *temp_stream = NULL;
2221 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2224 const gchar *content_type;
2225 content_type = tny_mime_part_get_content_type (mime_part);
2226 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2228 modest_platform_activate_file (filepath, content_type);
2229 g_object_unref (temp_stream);
2231 /* NOTE: files in the temporary area will be automatically
2232 * cleaned after some time if they are no longer in use */
2235 /* message attachment */
2236 TnyHeader *header = NULL;
2237 ModestWindowMgr *mgr;
2238 ModestWindow *msg_win = NULL;
2241 header = tny_msg_get_header (TNY_MSG (mime_part));
2242 mgr = modest_runtime_get_window_mgr ();
2243 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2246 if (msg_win) /* there is already a window for this uid; top it */
2247 gtk_window_present (GTK_WINDOW(msg_win));
2249 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2250 * thus, we don't do anything */
2251 g_warning ("window for is already being created");
2253 /* it's not found, so create a new window for it */
2254 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2255 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2257 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2258 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2259 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2260 modest_window_get_zoom (MODEST_WINDOW (window)));
2261 modest_window_mgr_register_window (mgr, msg_win);
2262 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2263 gtk_widget_show_all (GTK_WIDGET (msg_win));
2266 g_object_unref (mime_part);
2282 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2283 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2284 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2285 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2288 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2292 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2293 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2294 g_free (pair->filename);
2295 g_object_unref (pair->part);
2296 g_slice_free (SaveMimePartPair, pair);
2298 g_list_free (info->pairs);
2301 gtk_widget_destroy (info->banner);
2302 g_object_unref (info->banner);
2303 g_slice_free (SaveMimePartInfo, info);
2308 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2310 if (info->pairs != NULL) {
2311 save_mime_part_to_file (info);
2314 result = info->result;
2316 /* This is a GDK lock because we are an idle callback and
2317 * hildon_banner_show_information is or does Gtk+ code */
2319 gdk_threads_enter (); /* CHECKED */
2320 save_mime_part_info_free (info, TRUE);
2322 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2324 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2326 gdk_threads_leave (); /* CHECKED */
2333 save_mime_part_to_file (SaveMimePartInfo *info)
2335 GnomeVFSResult result;
2336 GnomeVFSHandle *handle;
2338 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2340 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0777);
2341 if (result == GNOME_VFS_OK) {
2342 stream = tny_vfs_stream_new (handle);
2343 tny_mime_part_decode_to_stream (pair->part, stream);
2344 g_object_unref (G_OBJECT (stream));
2345 g_object_unref (pair->part);
2346 g_slice_free (SaveMimePartPair, pair);
2347 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2348 info->result = TRUE;
2350 save_mime_part_info_free (info, FALSE);
2351 info->result = FALSE;
2354 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2359 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2361 gboolean is_ok = TRUE;
2362 gint replaced_files = 0;
2363 const GList *files = info->pairs;
2366 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2367 SaveMimePartPair *pair = iter->data;
2368 if (modest_maemo_utils_file_exists (pair->filename)) {
2372 if (replaced_files) {
2373 GtkWidget *confirm_overwrite_dialog;
2374 const gchar *message = (replaced_files == 1) ?
2375 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2376 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2377 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2380 gtk_widget_destroy (confirm_overwrite_dialog);
2384 save_mime_part_info_free (info, TRUE);
2386 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2387 _CS("sfil_ib_saving"));
2388 info->banner = g_object_ref (banner);
2389 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2390 g_object_unref (banner);
2397 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2399 gboolean clean_list = FALSE;
2400 ModestMsgViewWindowPrivate *priv;
2401 GList *files_to_save = NULL;
2402 GtkWidget *save_dialog = NULL;
2403 gchar *folder = NULL;
2404 gboolean canceled = FALSE;
2405 const gchar *filename = NULL;
2406 gchar *save_multiple_str = NULL;
2408 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2409 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2411 if (mime_parts == NULL) {
2412 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2413 if (mime_parts == NULL)
2418 /* prepare dialog */
2419 if (mime_parts->next == NULL) {
2420 /* only one attachment selected */
2421 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2422 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2423 filename = tny_mime_part_get_filename (mime_part);
2425 g_warning ("Tried to save a non-file attachment");
2429 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2430 g_list_length (mime_parts));
2433 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2434 GTK_FILE_CHOOSER_ACTION_SAVE);
2437 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2438 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2442 if (filename != NULL)
2443 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2446 /* if multiple, set multiple string */
2447 if (save_multiple_str) {
2448 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2452 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2453 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2455 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2456 hildon_banner_show_information
2457 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2461 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2462 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2464 if (tny_mime_part_is_attachment (mime_part)) {
2465 SaveMimePartPair *pair;
2467 if ((mime_parts->next != NULL) &&
2468 (tny_mime_part_get_filename (mime_part) == NULL))
2471 pair = g_slice_new0 (SaveMimePartPair);
2472 if (mime_parts->next == NULL) {
2473 pair->filename = g_strdup (chooser_uri);
2476 g_build_filename (chooser_uri,
2477 tny_mime_part_get_filename (mime_part), NULL);
2479 pair->part = g_object_ref (mime_part);
2480 files_to_save = g_list_prepend (files_to_save, pair);
2484 g_free (chooser_uri);
2487 gtk_widget_destroy (save_dialog);
2490 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2491 g_list_free (mime_parts);
2494 if (files_to_save != NULL) {
2495 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2496 info->pairs = files_to_save;
2497 info->result = TRUE;
2498 save_mime_parts_to_file_with_checks (info);
2503 show_remove_attachment_information (gpointer userdata)
2505 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2506 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2508 if (priv->remove_attachment_banner != NULL) {
2509 gtk_widget_destroy (priv->remove_attachment_banner);
2510 g_object_unref (priv->remove_attachment_banner);
2513 priv->remove_attachment_banner = g_object_ref (
2514 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2520 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2522 ModestMsgViewWindowPrivate *priv;
2523 GList *mime_parts = NULL, *node;
2524 gchar *confirmation_message;
2528 /* TnyFolder *folder; */
2530 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2531 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2534 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2536 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2538 /* Remove already purged messages from mime parts list */
2540 while (node != NULL) {
2541 TnyMimePart *part = TNY_MIME_PART (node->data);
2542 if (tny_mime_part_is_purged (part)) {
2543 GList *deleted_node = node;
2544 node = g_list_next (node);
2545 g_object_unref (part);
2546 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2548 node = g_list_next (node);
2552 if (mime_parts == NULL)
2555 n_attachments = g_list_length (mime_parts);
2556 if (n_attachments == 1) {
2557 const gchar *filename;
2559 if (TNY_IS_MSG (mime_parts->data)) {
2561 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2562 filename = tny_header_get_subject (header);
2563 g_object_unref (header);
2564 if (filename == NULL)
2565 filename = _("mail_va_no_subject");
2567 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2569 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2571 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2572 "mcen_nc_purge_files_text",
2573 n_attachments), n_attachments);
2575 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2576 confirmation_message);
2577 g_free (confirmation_message);
2579 if (response != GTK_RESPONSE_OK)
2582 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2583 /* folder = tny_msg_get_folder (msg); */
2584 /* tny_msg_uncache_attachments (msg); */
2585 /* tny_folder_refresh (folder, NULL); */
2586 /* g_object_unref (folder); */
2588 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2589 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2590 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2593 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2594 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2595 tny_msg_rewrite_cache (msg);
2596 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2598 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2599 g_list_free (mime_parts);
2601 if (priv->purge_timeout > 0) {
2602 g_source_remove (priv->purge_timeout);
2603 priv->purge_timeout = 0;
2606 if (priv->remove_attachment_banner) {
2607 gtk_widget_destroy (priv->remove_attachment_banner);
2608 g_object_unref (priv->remove_attachment_banner);
2609 priv->remove_attachment_banner = NULL;
2617 update_window_title (ModestMsgViewWindow *window)
2619 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2621 TnyHeader *header = NULL;
2622 const gchar *subject = NULL;
2624 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2626 header = tny_msg_get_header (msg);
2627 subject = tny_header_get_subject (header);
2628 g_object_unref (msg);
2631 if ((subject == NULL)||(subject[0] == '\0'))
2632 subject = _("mail_va_no_subject");
2634 gtk_window_set_title (GTK_WINDOW (window), subject);
2637 static void on_move_focus (ModestMsgViewWindow *window,
2638 GtkDirectionType direction,
2641 GtkWidget *current_focus = NULL;
2643 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2644 if ((current_focus != NULL) &&
2645 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2646 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");