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 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
517 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
518 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
519 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
521 #ifdef MODEST_USE_MOZEMBED
522 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (priv->main_scroll), priv->msg_view);
524 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
526 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
527 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
529 priv->find_toolbar = hildon_find_toolbar_new (NULL);
530 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
531 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
532 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
533 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
535 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);
536 gtk_widget_show_all (GTK_WIDGET(main_vbox));
540 modest_msg_view_window_disconnect_signals (ModestWindow *self)
542 ModestMsgViewWindowPrivate *priv;
543 ModestHeaderView *header_view = NULL;
544 ModestMainWindow *main_window = NULL;
545 ModestWindowMgr *window_mgr = NULL;
547 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
549 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
550 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
551 priv->clipboard_change_handler))
552 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
553 priv->clipboard_change_handler);
555 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
556 priv->queue_change_handler))
557 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
558 priv->queue_change_handler);
560 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
561 priv->account_removed_handler))
562 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
563 priv->account_removed_handler);
565 if (priv->header_model) {
566 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
567 priv->row_changed_handler))
568 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
569 priv->row_changed_handler);
571 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
572 priv->row_deleted_handler))
573 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
574 priv->row_deleted_handler);
576 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
577 priv->row_inserted_handler))
578 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
579 priv->row_inserted_handler);
581 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
582 priv->rows_reordered_handler))
583 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
584 priv->rows_reordered_handler);
587 window_mgr = modest_runtime_get_window_mgr();
588 g_assert(window_mgr != NULL);
590 main_window = MODEST_MAIN_WINDOW(
591 modest_window_mgr_get_main_window(window_mgr));
593 if(main_window == NULL)
596 header_view = MODEST_HEADER_VIEW(
597 modest_main_window_get_child_widget(
598 main_window, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
600 if (header_view == NULL)
603 modest_header_view_remove_observer(header_view,
604 MODEST_HEADER_VIEW_OBSERVER(self));
608 modest_msg_view_window_finalize (GObject *obj)
610 ModestMsgViewWindowPrivate *priv;
612 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
614 /* Sanity check: shouldn't be needed, the window mgr should
615 call this function before */
616 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
618 if (priv->header_model != NULL) {
619 g_object_unref (priv->header_model);
620 priv->header_model = NULL;
623 if (priv->progress_bar_timeout > 0) {
624 g_source_remove (priv->progress_bar_timeout);
625 priv->progress_bar_timeout = 0;
628 if (priv->remove_attachment_banner) {
629 gtk_widget_destroy (priv->remove_attachment_banner);
630 g_object_unref (priv->remove_attachment_banner);
631 priv->remove_attachment_banner = NULL;
634 if (priv->purge_timeout > 0) {
635 g_source_remove (priv->purge_timeout);
636 priv->purge_timeout = 0;
639 if (priv->row_reference) {
640 gtk_tree_row_reference_free (priv->row_reference);
641 priv->row_reference = NULL;
644 if (priv->next_row_reference) {
645 gtk_tree_row_reference_free (priv->next_row_reference);
646 priv->next_row_reference = NULL;
650 g_free (priv->msg_uid);
651 priv->msg_uid = NULL;
654 G_OBJECT_CLASS(parent_class)->finalize (obj);
658 select_next_valid_row (GtkTreeModel *model,
659 GtkTreeRowReference **row_reference,
662 GtkTreeIter tmp_iter;
663 GtkTreePath *path, *next;
664 gboolean retval = FALSE;
666 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
668 path = gtk_tree_row_reference_get_path (*row_reference);
669 gtk_tree_model_get_iter (model, &tmp_iter, path);
670 gtk_tree_row_reference_free (*row_reference);
671 *row_reference = NULL;
673 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
674 next = gtk_tree_model_get_path (model, &tmp_iter);
675 *row_reference = gtk_tree_row_reference_new (model, next);
677 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
678 next = gtk_tree_model_get_path (model, &tmp_iter);
680 /* Ensure that we are not selecting the same */
681 if (gtk_tree_path_compare (path, next) != 0) {
682 *row_reference = gtk_tree_row_reference_new (model, next);
688 gtk_tree_path_free (path);
693 /* TODO: This should be in _init(), with the parameters as properties. */
695 modest_msg_view_window_construct (ModestMsgViewWindow *self,
696 const gchar *modest_account_name,
697 const gchar *msg_uid)
700 ModestMsgViewWindowPrivate *priv = NULL;
701 ModestWindowPrivate *parent_priv = NULL;
702 ModestDimmingRulesGroup *menu_rules_group = NULL;
703 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
704 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
705 GtkActionGroup *action_group = NULL;
706 GError *error = NULL;
707 GdkPixbuf *window_icon;
709 obj = G_OBJECT (self);
710 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
711 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
713 priv->msg_uid = g_strdup (msg_uid);
715 parent_priv->ui_manager = gtk_ui_manager_new();
716 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
718 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
719 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
721 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
722 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
723 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
725 /* Add common actions */
726 gtk_action_group_add_actions (action_group,
727 modest_action_entries,
728 G_N_ELEMENTS (modest_action_entries),
730 gtk_action_group_add_toggle_actions (action_group,
731 modest_toggle_action_entries,
732 G_N_ELEMENTS (modest_toggle_action_entries),
734 gtk_action_group_add_toggle_actions (action_group,
735 msg_view_toggle_action_entries,
736 G_N_ELEMENTS (msg_view_toggle_action_entries),
738 gtk_action_group_add_radio_actions (action_group,
739 msg_view_zoom_action_entries,
740 G_N_ELEMENTS (msg_view_zoom_action_entries),
742 G_CALLBACK (modest_ui_actions_on_change_zoom),
745 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
746 g_object_unref (action_group);
748 /* Load the UI definition */
749 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
752 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
753 g_error_free (error);
758 /* Add common dimming rules */
759 modest_dimming_rules_group_add_rules (menu_rules_group,
760 modest_msg_view_menu_dimming_entries,
761 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
762 MODEST_WINDOW (self));
763 modest_dimming_rules_group_add_rules (toolbar_rules_group,
764 modest_msg_view_toolbar_dimming_entries,
765 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
766 MODEST_WINDOW (self));
767 modest_dimming_rules_group_add_rules (clipboard_rules_group,
768 modest_msg_view_clipboard_dimming_entries,
769 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
770 MODEST_WINDOW (self));
772 /* Insert dimming rules group for this window */
773 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
774 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
775 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
776 g_object_unref (menu_rules_group);
777 g_object_unref (toolbar_rules_group);
778 g_object_unref (clipboard_rules_group);
780 /* Add accelerators */
781 gtk_window_add_accel_group (GTK_WINDOW (obj),
782 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
785 init_window (MODEST_MSG_VIEW_WINDOW(obj));
786 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
788 /* Set window icon */
789 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
791 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
792 g_object_unref (window_icon);
795 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
797 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
798 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
799 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
800 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
801 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
802 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
803 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
804 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
805 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
806 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
808 g_signal_connect (G_OBJECT (obj), "key-release-event",
809 G_CALLBACK (modest_msg_view_window_key_release_event),
812 g_signal_connect (G_OBJECT (obj), "window-state-event",
813 G_CALLBACK (modest_msg_view_window_window_state_event),
816 g_signal_connect (G_OBJECT (obj), "move-focus",
817 G_CALLBACK (on_move_focus), obj);
819 /* Mail Operation Queue */
820 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
822 G_CALLBACK (on_queue_changed),
825 /* Account manager */
826 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
828 G_CALLBACK(on_account_removed),
831 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
833 priv->last_search = NULL;
835 /* Init the clipboard actions dim status */
836 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
838 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
840 /* Check toolbar dimming rules */
841 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
842 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
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 ModestMainWindow *main_window = NULL;
858 ModestWindowMgr *window_mgr = NULL;
860 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
861 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: */
868 window_mgr = modest_runtime_get_window_mgr();
869 g_assert(window_mgr != NULL);
870 main_window = MODEST_MAIN_WINDOW(
871 modest_window_mgr_get_main_window(window_mgr));
872 g_assert(main_window != NULL);
873 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
874 main_window, MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
875 if (header_view != NULL){
876 header_folder = modest_header_view_get_folder(header_view);
877 g_assert(header_folder != NULL);
878 priv->header_folder_id = tny_folder_get_id(header_folder);
879 g_assert(priv->header_folder_id != NULL);
880 g_object_unref(header_folder);
883 priv->header_model = g_object_ref(model);
884 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
885 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
886 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
888 priv->row_changed_handler = g_signal_connect(
889 GTK_TREE_MODEL(model), "row-changed",
890 G_CALLBACK(modest_msg_view_window_on_row_changed),
892 priv->row_deleted_handler = g_signal_connect(
893 GTK_TREE_MODEL(model), "row-deleted",
894 G_CALLBACK(modest_msg_view_window_on_row_deleted),
896 priv->row_inserted_handler = g_signal_connect (
897 GTK_TREE_MODEL(model), "row-inserted",
898 G_CALLBACK(modest_msg_view_window_on_row_inserted),
900 priv->rows_reordered_handler = g_signal_connect(
901 GTK_TREE_MODEL(model), "rows-reordered",
902 G_CALLBACK(modest_msg_view_window_on_row_reordered),
905 if (header_view != NULL){
906 modest_header_view_add_observer(header_view,
907 MODEST_HEADER_VIEW_OBSERVER(window));
910 gtk_widget_show_all (GTK_WIDGET (window));
912 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
914 modest_msg_view_window_update_priority (window);
916 /* Check toolbar dimming rules */
917 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
919 return MODEST_WINDOW(window);
923 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
924 const gchar *modest_account_name,
925 const gchar *msg_uid)
927 ModestMsgViewWindow *window = NULL;
928 ModestMsgViewWindowPrivate *priv = NULL;
930 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
931 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
932 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
934 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
936 /* Remember that this is a search result,
937 * so we can disable some UI appropriately: */
938 priv->is_search_result = TRUE;
940 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
942 return MODEST_WINDOW(window);
946 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
947 const gchar *modest_account_name,
948 const gchar *msg_uid)
951 ModestMsgViewWindowPrivate *priv;
952 g_return_val_if_fail (msg, NULL);
954 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
955 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
956 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
957 modest_account_name, msg_uid);
959 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
961 return MODEST_WINDOW(obj);
964 void modest_msg_view_window_on_row_changed(
965 GtkTreeModel *header_model,
968 ModestMsgViewWindow *window){
969 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
972 void modest_msg_view_window_on_row_deleted(
973 GtkTreeModel *header_model,
975 ModestMsgViewWindow *window){
976 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
979 /* On insertions we check if the folder still has the message we are
980 * showing or do not. If do not, we do nothing. Which means we are still
981 * not attached to any header folder and thus next/prev buttons are
982 * still dimmed. Once the message that is shown by msg-view is found, the
983 * new model of header-view will be attached and the references will be set.
984 * On each further insertions dimming rules will be checked. However
985 * this requires extra CPU time at least works.
986 * (An message might be deleted from TnyFolder and thus will not be
987 * inserted into the model again for example if it is removed by the
988 * imap server and the header view is refreshed.)
990 void modest_msg_view_window_on_row_inserted(
991 GtkTreeModel *new_model,
992 GtkTreePath *tree_path,
993 GtkTreeIter *tree_iter,
994 ModestMsgViewWindow *window){
995 ModestMsgViewWindowPrivate *priv = NULL;
996 TnyHeader *header = NULL;
999 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1001 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1003 /* If we already has a model attached then the message shown by
1004 * msg-view is in it, and thus we do not need any actions but
1005 * to check the dimming rules.*/
1006 if(priv->header_model != NULL){
1007 gtk_tree_row_reference_free(priv->next_row_reference);
1008 priv->next_row_reference = gtk_tree_row_reference_copy(
1009 priv->row_reference);
1010 select_next_valid_row (priv->header_model,
1011 &(priv->next_row_reference), FALSE);
1012 modest_ui_actions_check_toolbar_dimming_rules (
1013 MODEST_WINDOW (window));
1017 /* Check if the newly inserted message is the same we are actually
1018 * showing. IF not, we should remain detached from the header model
1019 * and thus prev and next toolbarbuttons should remain dimmed. */
1020 gtk_tree_model_get (new_model, tree_iter,
1021 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1022 uid = modest_tny_folder_get_header_unique_id(header);
1023 if(!g_str_equal(priv->msg_uid, uid)){
1029 /* Setup row_reference for the actual msg. */
1030 priv->row_reference = gtk_tree_row_reference_new(
1031 new_model, tree_path);
1032 if(priv->row_reference == NULL){
1033 g_warning("No reference for msg header item.");
1037 /* Attach new_model and connect some callback to it to become able
1038 * to detect changes in header-view. */
1039 priv->header_model = g_object_ref(new_model);
1040 g_signal_connect (new_model, "row-changed",
1041 G_CALLBACK (modest_msg_view_window_on_row_changed),
1043 g_signal_connect (new_model, "row-deleted",
1044 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1046 g_signal_connect (new_model, "rows-reordered",
1047 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1050 /* Now set up next_row_reference. */
1051 priv->next_row_reference = gtk_tree_row_reference_copy(
1052 priv->row_reference);
1053 select_next_valid_row (priv->header_model,
1054 &(priv->next_row_reference), FALSE);
1056 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1059 void modest_msg_view_window_on_row_reordered(
1060 GtkTreeModel *header_model,
1064 ModestMsgViewWindow *window){
1065 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1068 /* The modest_msg_view_window_update_model_replaced implements update
1069 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1070 * actually belongs to the header-view is the same as the TnyFolder of
1071 * the message of msg-view or not. If they are different, there is
1072 * nothing to do. If they are the same, then the model has replaced and
1073 * the reference in msg-view shall be replaced from the old model to
1074 * the new model. In this case the view will be detached from it's
1075 * header folder. From this point the next/prev buttons are dimmed.
1077 void modest_msg_view_window_update_model_replaced(
1078 ModestHeaderViewObserver *observer,
1079 GtkTreeModel *model,
1080 const gchar *tny_folder_id){
1081 ModestMsgViewWindowPrivate *priv = NULL;
1082 ModestMsgViewWindow *window = NULL;
1084 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1085 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1087 window = MODEST_MSG_VIEW_WINDOW(observer);
1088 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1090 /* If there is an other folder in the header-view then we do
1091 * not care about it's model (msg list). Else if the
1092 * header-view shows the folder the msg shown by us is in, we
1093 * shall replace our model reference and make some check. */
1094 if(tny_folder_id == NULL ||
1095 !g_str_equal(tny_folder_id, priv->header_folder_id))
1098 /* Model is changed(replaced), so we should forget the old
1099 * one. Because there might be other references and there
1100 * might be some change on the model even if we unreferenced
1101 * it, we need to disconnect our signals here. */
1102 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1103 priv->row_changed_handler))
1104 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1105 priv->row_changed_handler);
1106 priv->row_changed_handler = 0;
1107 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1108 priv->row_deleted_handler))
1109 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1110 priv->row_deleted_handler);
1111 priv->row_deleted_handler = 0;
1112 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1113 priv->row_inserted_handler))
1114 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1115 priv->row_inserted_handler);
1116 priv->row_inserted_handler = 0;
1117 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1118 priv->rows_reordered_handler))
1119 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1120 priv->rows_reordered_handler);
1121 priv->rows_reordered_handler = 0;
1122 g_object_unref(priv->header_model);
1123 priv->header_model = NULL;
1124 g_object_unref(priv->row_reference);
1125 priv->row_reference = NULL;
1126 g_object_unref(priv->next_row_reference);
1127 priv->next_row_reference = NULL;
1129 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1131 if(tny_folder_id == NULL)
1134 g_assert(model != NULL);
1136 /* Also we must connect to the new model for row insertions.
1137 * Only for insertions now. We will need other ones only after
1138 * the msg is show by msg-view is added to the new model. */
1139 priv->row_inserted_handler = g_signal_connect (
1140 model, "row-inserted",
1141 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1146 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1148 ModestMsgViewWindowPrivate *priv= NULL;
1150 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1151 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1153 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1157 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1159 ModestMsgViewWindowPrivate *priv= NULL;
1161 TnyHeader *header = NULL;
1162 GtkTreePath *path = NULL;
1165 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1166 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1168 /* If the message was not obtained from a treemodel,
1169 * for instance if it was opened directly by the search UI:
1171 if (priv->header_model == NULL) {
1172 msg = modest_msg_view_window_get_message (self);
1174 header = tny_msg_get_header (msg);
1175 g_object_unref (msg);
1180 /* Get iter of the currently selected message in the header view: */
1181 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1182 * instead of sometimes retrieving it from the header view?
1183 * Then we wouldn't be dependent on the message actually still being selected
1184 * in the header view. murrayc. */
1185 if (!gtk_tree_row_reference_valid (priv->row_reference))
1187 path = gtk_tree_row_reference_get_path (priv->row_reference);
1188 g_return_val_if_fail (path != NULL, NULL);
1189 gtk_tree_model_get_iter (priv->header_model,
1193 /* Get current message header */
1194 gtk_tree_model_get (priv->header_model, &iter,
1195 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1198 gtk_tree_path_free (path);
1203 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1205 ModestMsgView *msg_view;
1206 ModestMsgViewWindowPrivate *priv;
1208 g_return_val_if_fail (self, NULL);
1210 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1212 msg_view = MODEST_MSG_VIEW (priv->msg_view);
1214 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1218 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1220 ModestMsgViewWindowPrivate *priv;
1222 g_return_val_if_fail (self, NULL);
1224 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1226 return (const gchar*) priv->msg_uid;
1230 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1233 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1234 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1235 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1239 is_active = gtk_toggle_action_get_active (toggle);
1242 gtk_widget_show (priv->find_toolbar);
1243 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1245 gtk_widget_hide (priv->find_toolbar);
1248 /* update the toggle buttons status */
1249 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1250 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1251 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1252 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1257 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1258 ModestMsgViewWindow *obj)
1260 GtkToggleAction *toggle;
1261 ModestWindowPrivate *parent_priv;
1262 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1264 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1265 gtk_toggle_action_set_active (toggle, FALSE);
1269 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1270 ModestMsgViewWindow *obj)
1272 gchar *current_search;
1273 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1275 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1276 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1280 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1282 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1283 g_free (current_search);
1284 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1288 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1290 g_free (priv->last_search);
1291 priv->last_search = g_strdup (current_search);
1292 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1295 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1296 g_free (priv->last_search);
1297 priv->last_search = NULL;
1299 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1302 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1303 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1304 g_free (priv->last_search);
1305 priv->last_search = NULL;
1307 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1311 g_free (current_search);
1316 modest_msg_view_window_set_zoom (ModestWindow *window,
1319 ModestMsgViewWindowPrivate *priv;
1320 ModestWindowPrivate *parent_priv;
1321 GtkAction *action = NULL;
1322 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1324 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1326 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1327 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1328 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1331 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1333 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1337 modest_msg_view_window_get_zoom (ModestWindow *window)
1339 ModestMsgViewWindowPrivate *priv;
1341 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1343 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1344 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1348 modest_msg_view_window_zoom_plus (ModestWindow *window)
1350 ModestWindowPrivate *parent_priv;
1351 GtkRadioAction *zoom_radio_action;
1352 GSList *group, *node;
1354 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1355 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1356 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1358 group = gtk_radio_action_get_group (zoom_radio_action);
1360 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1361 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1365 for (node = group; node != NULL; node = g_slist_next (node)) {
1366 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1367 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1375 modest_msg_view_window_zoom_minus (ModestWindow *window)
1377 ModestWindowPrivate *parent_priv;
1378 GtkRadioAction *zoom_radio_action;
1379 GSList *group, *node;
1381 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1382 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1383 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1385 group = gtk_radio_action_get_group (zoom_radio_action);
1387 for (node = group; node != NULL; node = g_slist_next (node)) {
1388 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1389 if (node->next != NULL) {
1390 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1393 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1403 modest_msg_view_window_key_release_event (GtkWidget *window,
1407 if (event->type == GDK_KEY_RELEASE) {
1408 switch (event->keyval) {
1410 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1414 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1427 modest_msg_view_window_scroll_up (ModestWindow *window)
1429 ModestMsgViewWindowPrivate *priv;
1430 gboolean return_value;
1432 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1433 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1437 modest_msg_view_window_scroll_down (ModestWindow *window)
1439 ModestMsgViewWindowPrivate *priv;
1440 gboolean return_value;
1442 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1443 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1447 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1450 ModestMsgViewWindowPrivate *priv;
1451 GtkTreeIter tmp_iter;
1452 gboolean is_last_selected;
1454 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1455 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1457 /*if no model (so no rows at all), then virtually we are the last*/
1458 if (!priv->header_model)
1461 path = gtk_tree_row_reference_get_path (priv->row_reference);
1465 is_last_selected = TRUE;
1466 while (is_last_selected) {
1468 gtk_tree_path_next (path);
1469 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1471 gtk_tree_model_get (priv->header_model, &tmp_iter,
1472 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1474 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1475 is_last_selected = FALSE;
1477 gtk_tree_path_free (path);
1478 return is_last_selected;
1482 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1484 ModestMsgViewWindowPrivate *priv;
1486 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1487 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1489 return priv->header_model != NULL;
1493 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1495 ModestMsgViewWindowPrivate *priv;
1497 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1498 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1500 return priv->is_search_result;
1504 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1507 ModestMsgViewWindowPrivate *priv;
1508 gboolean is_first_selected;
1509 GtkTreeIter tmp_iter;
1510 /* gchar * path_string;*/
1512 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1513 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1515 /*if no model (so no rows at all), then virtually we are the first*/
1516 if (!priv->header_model)
1519 path = gtk_tree_row_reference_get_path (priv->row_reference);
1523 /* path_string = gtk_tree_path_to_string (path);
1524 is_first_selected = strcmp (path_string, "0");
1526 g_free (path_string);
1527 gtk_tree_path_free (path);
1529 return is_first_selected;*/
1531 is_first_selected = TRUE;
1532 while (is_first_selected) {
1534 if(!gtk_tree_path_prev (path))
1536 /* Here the 'if' is needless for logic, but let make sure
1537 * iter is valid for gtk_tree_model_get. */
1538 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1540 gtk_tree_model_get (priv->header_model, &tmp_iter,
1541 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1543 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1544 is_first_selected = FALSE;
1546 gtk_tree_path_free (path);
1547 return is_first_selected;
1551 * Reads the message whose summary item is @header. It takes care of
1552 * several things, among others:
1554 * If the message was not previously downloaded then ask the user
1555 * before downloading. If there is no connection launch the connection
1556 * dialog. Update toolbar dimming rules.
1558 * Returns: TRUE if the mail operation was started, otherwise if the
1559 * user do not want to download the message, or if the user do not
1560 * want to connect, then the operation is not issued
1563 message_reader (ModestMsgViewWindow *window,
1564 ModestMsgViewWindowPrivate *priv,
1566 GtkTreeRowReference *row_reference)
1568 ModestMailOperation *mail_op = NULL;
1569 ModestMailOperationTypeOperation op_type;
1570 gboolean already_showing = FALSE;
1571 ModestWindow *msg_window = NULL;
1572 ModestWindowMgr *mgr;
1574 g_return_val_if_fail (row_reference != NULL, FALSE);
1576 mgr = modest_runtime_get_window_mgr ();
1577 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1578 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1581 gtk_window_present (GTK_WINDOW (msg_window));
1582 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1586 /* Msg download completed */
1587 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1588 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1590 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1592 /* Ask the user if he wants to download the message if
1594 if (!tny_device_is_online (modest_runtime_get_device())) {
1595 TnyFolder *folder = NULL;
1596 GtkResponseType response;
1598 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1599 _("mcen_nc_get_msg"));
1600 if (response == GTK_RESPONSE_CANCEL)
1603 /* Offer the connection dialog if necessary */
1604 folder = tny_header_get_folder (header);
1606 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1607 TNY_FOLDER_STORE (folder))) {
1608 g_object_unref (folder);
1611 g_object_unref (folder);
1616 /* New mail operation */
1617 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1618 modest_ui_actions_get_msgs_full_error_handler,
1621 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1622 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1623 g_object_unref (mail_op);
1625 /* Update toolbar dimming rules */
1626 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1632 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1634 ModestMsgViewWindowPrivate *priv;
1635 GtkTreePath *path= NULL;
1636 GtkTreeIter tmp_iter;
1638 gboolean retval = TRUE;
1639 GtkTreeRowReference *row_reference = NULL;
1641 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1642 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1644 /* Update the next row reference if it's not valid. This could
1645 happen if for example the header which it was pointing to,
1646 was deleted. The best place to do it is in the row-deleted
1647 handler but the tinymail model do not work like the glib
1648 tree models and reports the deletion when the row is still
1650 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1651 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1652 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1653 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1656 if (priv->next_row_reference)
1657 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1661 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1663 gtk_tree_model_get_iter (priv->header_model,
1666 gtk_tree_path_free (path);
1668 gtk_tree_model_get (priv->header_model, &tmp_iter,
1669 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1672 /* Read the message & show it */
1673 if (!message_reader (window, priv, header, row_reference)) {
1675 gtk_tree_row_reference_free (row_reference);
1679 g_object_unref (header);
1685 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1687 ModestMsgViewWindowPrivate *priv = NULL;
1688 TnyHeader *header = NULL;
1690 GtkTreePath *path = NULL;
1691 GtkTreeRowReference *row_reference = NULL;
1693 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1694 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1696 /* Check that the model is not empty */
1697 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1700 /* Get the header */
1701 gtk_tree_model_get (priv->header_model,
1703 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1705 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1706 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1707 g_object_unref (header);
1708 return modest_msg_view_window_select_next_message (self);
1711 path = gtk_tree_model_get_path (priv->header_model, &iter);
1712 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1713 gtk_tree_path_free (path);
1715 /* Read the message & show it */
1716 message_reader (self, priv, header, row_reference);
1719 g_object_unref (header);
1725 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1727 ModestMsgViewWindowPrivate *priv = NULL;
1729 GtkTreeRowReference *row_reference = NULL;
1731 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1732 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1734 /* Return inmediatly if there is no header model */
1735 if (!priv->header_model)
1738 path = gtk_tree_row_reference_get_path (priv->row_reference);
1739 while (gtk_tree_path_prev (path)) {
1743 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1744 gtk_tree_model_get (priv->header_model, &iter,
1745 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1749 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1750 g_object_unref (header);
1754 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1755 /* Read the message & show it */
1756 if (!message_reader (window, priv, header, row_reference)) {
1757 gtk_tree_row_reference_free (row_reference);
1758 g_object_unref (header);
1762 gtk_tree_path_free (path);
1763 g_object_unref (header);
1768 gtk_tree_path_free (path);
1773 view_msg_cb (ModestMailOperation *mail_op,
1778 ModestMsgViewWindow *self = NULL;
1779 ModestMsgViewWindowPrivate *priv = NULL;
1780 GtkTreeRowReference *row_reference = NULL;
1782 /* If there was any error */
1783 row_reference = (GtkTreeRowReference *) user_data;
1784 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1785 gtk_tree_row_reference_free (row_reference);
1789 /* Get the window */
1790 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1791 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1792 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1794 /* Update the row reference */
1795 gtk_tree_row_reference_free (priv->row_reference);
1796 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1797 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1798 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1799 gtk_tree_row_reference_free (row_reference);
1801 /* Mark header as read */
1802 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1803 tny_header_set_flags (header, TNY_HEADER_FLAG_SEEN);
1805 /* Set new message */
1806 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1807 modest_msg_view_window_update_priority (self);
1808 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1809 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1811 /* Set the new message uid of the window */
1812 if (priv->msg_uid) {
1813 g_free (priv->msg_uid);
1814 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1817 /* Notify the observers */
1818 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1819 0, priv->header_model, priv->row_reference);
1821 /* Free new references */
1822 g_object_unref (self);
1826 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1828 ModestMsgViewWindowPrivate *priv;
1830 TnyFolderType folder_type;
1832 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1834 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1836 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1840 folder = tny_msg_get_folder (msg);
1842 folder_type = tny_folder_get_folder_type (folder);
1843 g_object_unref (folder);
1845 g_object_unref (msg);
1853 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1855 ModestMsgViewWindowPrivate *priv;
1856 TnyHeaderFlags flags = 0;
1858 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1860 if (priv->header_model) {
1863 GtkTreePath *path = NULL;
1865 path = gtk_tree_row_reference_get_path (priv->row_reference);
1866 g_return_if_fail (path != NULL);
1867 gtk_tree_model_get_iter (priv->header_model,
1869 gtk_tree_row_reference_get_path (priv->row_reference));
1871 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1873 flags = tny_header_get_flags (header);
1874 gtk_tree_path_free (path);
1877 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1882 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1884 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1885 ModestWindowPrivate *parent_priv;
1886 ModestWindowMgr *mgr;
1887 gboolean is_fullscreen;
1888 GtkAction *fs_toggle_action;
1891 mgr = modest_runtime_get_window_mgr ();
1892 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1894 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1896 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1897 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1898 if (is_fullscreen != active) {
1899 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1908 set_homogeneous (GtkWidget *widget,
1911 if (GTK_IS_TOOL_ITEM (widget)) {
1912 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1913 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1918 modest_msg_view_window_show_toolbar (ModestWindow *self,
1919 gboolean show_toolbar)
1921 ModestMsgViewWindowPrivate *priv = NULL;
1922 ModestWindowPrivate *parent_priv;
1923 GtkWidget *reply_button = NULL, *menu = NULL;
1924 GtkWidget *placeholder = NULL;
1926 const gchar *action_name;
1929 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1930 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1932 /* Set optimized view status */
1933 priv->optimized_view = !show_toolbar;
1935 if (!parent_priv->toolbar) {
1936 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1938 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1940 /* Set homogeneous toolbar */
1941 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1942 set_homogeneous, NULL);
1944 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1945 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1946 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1947 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1948 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1949 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1950 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1951 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1953 /* Add ProgressBar (Transfer toolbar) */
1954 priv->progress_bar = modest_progress_bar_widget_new ();
1955 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1956 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1957 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1958 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1959 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1961 /* Connect cancel 'clicked' signal to abort progress mode */
1962 g_signal_connect(priv->cancel_toolitem, "clicked",
1963 G_CALLBACK(cancel_progressbar),
1966 /* Add it to the observers list */
1967 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1970 hildon_window_add_toolbar (HILDON_WINDOW (self),
1971 GTK_TOOLBAR (parent_priv->toolbar));
1974 /* Set reply button tap and hold menu */
1975 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1976 "/ToolBar/ToolbarMessageReply");
1977 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1978 "/ToolbarReplyCSM");
1979 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1983 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1984 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1985 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1987 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1988 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1991 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1992 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1995 /* Update also the actions (to update the toggles in the
1996 menus), we have to do it manually because some other window
1997 of the same time could have changed it (remember that the
1998 toolbar fullscreen mode is shared by all the windows of the
2000 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2001 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2003 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2005 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2006 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2011 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2013 ModestMsgViewWindow *window)
2015 if (!GTK_WIDGET_VISIBLE (window))
2018 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2022 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2024 ModestMsgViewWindowPrivate *priv;
2026 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2027 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2029 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2033 cancel_progressbar (GtkToolButton *toolbutton,
2034 ModestMsgViewWindow *self)
2037 ModestMsgViewWindowPrivate *priv;
2039 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2041 /* Get operation observers and cancel its current operation */
2042 tmp = priv->progress_widgets;
2044 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2045 tmp=g_slist_next(tmp);
2049 observers_empty (ModestMsgViewWindow *self)
2052 ModestMsgViewWindowPrivate *priv;
2053 gboolean is_empty = TRUE;
2054 guint pending_ops = 0;
2056 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2057 tmp = priv->progress_widgets;
2059 /* Check all observers */
2060 while (tmp && is_empty) {
2061 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2062 is_empty = pending_ops == 0;
2064 tmp = g_slist_next(tmp);
2071 on_account_removed (TnyAccountStore *account_store,
2072 TnyAccount *account,
2075 /* Do nothing if it's a transport account, because we only
2076 show the messages of a store account */
2077 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2078 const gchar *parent_acc = NULL;
2079 const gchar *our_acc = NULL;
2081 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2082 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2084 /* Close this window if I'm showing a message of the removed account */
2085 if (strcmp (parent_acc, our_acc) == 0)
2086 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2091 on_queue_changed (ModestMailOperationQueue *queue,
2092 ModestMailOperation *mail_op,
2093 ModestMailOperationQueueNotification type,
2094 ModestMsgViewWindow *self)
2097 ModestMsgViewWindowPrivate *priv;
2098 ModestMailOperationTypeOperation op_type;
2099 ModestToolBarModes mode;
2101 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2102 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2104 /* If this operations was created by another window, do nothing */
2105 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2108 /* Get toolbar mode from operation id*/
2109 op_type = modest_mail_operation_get_type_operation (mail_op);
2111 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2112 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2113 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2114 mode = TOOLBAR_MODE_TRANSFER;
2117 mode = TOOLBAR_MODE_NORMAL;
2121 /* Add operation observers and change toolbar if neccessary*/
2122 tmp = priv->progress_widgets;
2124 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2125 if (mode == TOOLBAR_MODE_TRANSFER) {
2126 /* Enable transfer toolbar mode */
2127 set_toolbar_transfer_mode(self);
2129 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2131 tmp = g_slist_next (tmp);
2136 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2137 if (mode == TOOLBAR_MODE_TRANSFER) {
2139 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2141 tmp = g_slist_next (tmp);
2145 /* If no more operations are being observed, NORMAL mode is enabled again */
2146 if (observers_empty (self)) {
2147 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2155 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2157 ModestMsgViewWindowPrivate *priv;
2158 GList *selected_attachments = NULL;
2160 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2161 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2163 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2165 return selected_attachments;
2169 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2171 ModestMsgViewWindowPrivate *priv;
2172 const gchar *msg_uid;
2173 gchar *attachment_uid = NULL;
2174 gint attachment_index = 0;
2177 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2178 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2179 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2181 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2182 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2183 attachment_index = g_list_index (attachments, mime_part);
2184 g_list_free (attachments);
2186 if (msg_uid && attachment_index >= 0) {
2187 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2190 if (mime_part == NULL) {
2191 gboolean error = FALSE;
2192 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2193 if (selected_attachments == NULL) {
2195 } else if (g_list_length (selected_attachments) > 1) {
2196 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2199 mime_part = (TnyMimePart *) selected_attachments->data;
2200 g_object_ref (mime_part);
2202 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2203 g_list_free (selected_attachments);
2208 g_object_ref (mime_part);
2211 if (tny_mime_part_is_purged (mime_part)) {
2212 g_object_unref (mime_part);
2216 if (!TNY_IS_MSG (mime_part)) {
2217 gchar *filepath = NULL;
2218 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2219 TnyFsStream *temp_stream = NULL;
2220 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2223 const gchar *content_type;
2224 content_type = tny_mime_part_get_content_type (mime_part);
2225 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2227 modest_platform_activate_file (filepath, content_type);
2228 g_object_unref (temp_stream);
2230 /* NOTE: files in the temporary area will be automatically
2231 * cleaned after some time if they are no longer in use */
2234 /* message attachment */
2235 TnyHeader *header = NULL;
2236 ModestWindowMgr *mgr;
2237 ModestWindow *msg_win = NULL;
2240 header = tny_msg_get_header (TNY_MSG (mime_part));
2241 mgr = modest_runtime_get_window_mgr ();
2242 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2245 if (msg_win) /* there is already a window for this uid; top it */
2246 gtk_window_present (GTK_WINDOW(msg_win));
2248 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2249 * thus, we don't do anything */
2250 g_warning ("window for is already being created");
2252 /* it's not found, so create a new window for it */
2253 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2254 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2256 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2257 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2258 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2259 modest_window_get_zoom (MODEST_WINDOW (window)));
2260 modest_window_mgr_register_window (mgr, msg_win);
2261 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2262 gtk_widget_show_all (GTK_WIDGET (msg_win));
2265 g_object_unref (mime_part);
2281 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2282 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2283 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2284 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2287 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2291 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2292 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2293 g_free (pair->filename);
2294 g_object_unref (pair->part);
2295 g_slice_free (SaveMimePartPair, pair);
2297 g_list_free (info->pairs);
2300 gtk_widget_destroy (info->banner);
2301 g_object_unref (info->banner);
2302 g_slice_free (SaveMimePartInfo, info);
2307 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2309 if (info->pairs != NULL) {
2310 save_mime_part_to_file (info);
2313 result = info->result;
2315 /* This is a GDK lock because we are an idle callback and
2316 * hildon_banner_show_information is or does Gtk+ code */
2318 gdk_threads_enter (); /* CHECKED */
2319 save_mime_part_info_free (info, TRUE);
2321 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2323 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2325 gdk_threads_leave (); /* CHECKED */
2332 save_mime_part_to_file (SaveMimePartInfo *info)
2334 GnomeVFSResult result;
2335 GnomeVFSHandle *handle;
2337 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2339 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0777);
2340 if (result == GNOME_VFS_OK) {
2341 stream = tny_vfs_stream_new (handle);
2342 tny_mime_part_decode_to_stream (pair->part, stream);
2343 g_object_unref (G_OBJECT (stream));
2344 g_object_unref (pair->part);
2345 g_slice_free (SaveMimePartPair, pair);
2346 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2347 info->result = TRUE;
2349 save_mime_part_info_free (info, FALSE);
2350 info->result = FALSE;
2353 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2358 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2360 gboolean is_ok = TRUE;
2361 gint replaced_files = 0;
2362 const GList *files = info->pairs;
2365 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2366 SaveMimePartPair *pair = iter->data;
2367 if (modest_maemo_utils_file_exists (pair->filename)) {
2371 if (replaced_files) {
2372 GtkWidget *confirm_overwrite_dialog;
2373 const gchar *message = (replaced_files == 1) ?
2374 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2375 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2376 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2379 gtk_widget_destroy (confirm_overwrite_dialog);
2383 save_mime_part_info_free (info, TRUE);
2385 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2386 _CS("sfil_ib_saving"));
2387 info->banner = g_object_ref (banner);
2388 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2389 g_object_unref (banner);
2396 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2398 gboolean clean_list = FALSE;
2399 ModestMsgViewWindowPrivate *priv;
2400 GList *files_to_save = NULL;
2401 GtkWidget *save_dialog = NULL;
2402 gchar *folder = NULL;
2403 gboolean canceled = FALSE;
2404 const gchar *filename = NULL;
2405 gchar *save_multiple_str = NULL;
2407 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2408 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2410 if (mime_parts == NULL) {
2411 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2412 if (mime_parts == NULL)
2417 /* prepare dialog */
2418 if (mime_parts->next == NULL) {
2419 /* only one attachment selected */
2420 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2421 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2422 filename = tny_mime_part_get_filename (mime_part);
2424 g_warning ("Tried to save a non-file attachment");
2428 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2429 g_list_length (mime_parts));
2432 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2433 GTK_FILE_CHOOSER_ACTION_SAVE);
2436 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2437 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2441 if (filename != NULL)
2442 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2445 /* if multiple, set multiple string */
2446 if (save_multiple_str) {
2447 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2451 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2452 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2454 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2455 hildon_banner_show_information
2456 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2460 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2461 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2463 if (tny_mime_part_is_attachment (mime_part)) {
2464 SaveMimePartPair *pair;
2466 if ((mime_parts->next != NULL) &&
2467 (tny_mime_part_get_filename (mime_part) == NULL))
2470 pair = g_slice_new0 (SaveMimePartPair);
2471 if (mime_parts->next == NULL) {
2472 pair->filename = g_strdup (chooser_uri);
2475 g_build_filename (chooser_uri,
2476 tny_mime_part_get_filename (mime_part), NULL);
2478 pair->part = g_object_ref (mime_part);
2479 files_to_save = g_list_prepend (files_to_save, pair);
2483 g_free (chooser_uri);
2486 gtk_widget_destroy (save_dialog);
2489 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2490 g_list_free (mime_parts);
2493 if (files_to_save != NULL) {
2494 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2495 info->pairs = files_to_save;
2496 info->result = TRUE;
2497 save_mime_parts_to_file_with_checks (info);
2502 show_remove_attachment_information (gpointer userdata)
2504 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2505 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2507 if (priv->remove_attachment_banner != NULL) {
2508 gtk_widget_destroy (priv->remove_attachment_banner);
2509 g_object_unref (priv->remove_attachment_banner);
2512 priv->remove_attachment_banner = g_object_ref (
2513 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2519 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2521 ModestMsgViewWindowPrivate *priv;
2522 GList *mime_parts = NULL, *node;
2523 gchar *confirmation_message;
2527 /* TnyFolder *folder; */
2529 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2530 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2533 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2535 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2537 /* Remove already purged messages from mime parts list */
2539 while (node != NULL) {
2540 TnyMimePart *part = TNY_MIME_PART (node->data);
2541 if (tny_mime_part_is_purged (part)) {
2542 GList *deleted_node = node;
2543 node = g_list_next (node);
2544 g_object_unref (part);
2545 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2547 node = g_list_next (node);
2551 if (mime_parts == NULL)
2554 n_attachments = g_list_length (mime_parts);
2555 if (n_attachments == 1) {
2556 const gchar *filename;
2558 if (TNY_IS_MSG (mime_parts->data)) {
2560 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2561 filename = tny_header_get_subject (header);
2562 g_object_unref (header);
2563 if (filename == NULL)
2564 filename = _("mail_va_no_subject");
2566 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2568 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2570 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2571 "mcen_nc_purge_files_text",
2572 n_attachments), n_attachments);
2574 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2575 confirmation_message);
2576 g_free (confirmation_message);
2578 if (response != GTK_RESPONSE_OK)
2581 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2582 /* folder = tny_msg_get_folder (msg); */
2583 /* tny_msg_uncache_attachments (msg); */
2584 /* tny_folder_refresh (folder, NULL); */
2585 /* g_object_unref (folder); */
2587 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2588 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2589 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2592 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2593 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2594 tny_msg_rewrite_cache (msg);
2595 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2597 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2598 g_list_free (mime_parts);
2600 if (priv->purge_timeout > 0) {
2601 g_source_remove (priv->purge_timeout);
2602 priv->purge_timeout = 0;
2605 if (priv->remove_attachment_banner) {
2606 gtk_widget_destroy (priv->remove_attachment_banner);
2607 g_object_unref (priv->remove_attachment_banner);
2608 priv->remove_attachment_banner = NULL;
2616 update_window_title (ModestMsgViewWindow *window)
2618 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2620 TnyHeader *header = NULL;
2621 const gchar *subject = NULL;
2623 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2625 header = tny_msg_get_header (msg);
2626 subject = tny_header_get_subject (header);
2627 g_object_unref (msg);
2630 if ((subject == NULL)||(subject[0] == '\0'))
2631 subject = _("mail_va_no_subject");
2633 gtk_window_set_title (GTK_WINDOW (window), subject);
2636 static void on_move_focus (ModestMsgViewWindow *window,
2637 GtkDirectionType direction,
2640 GtkWidget *current_focus = NULL;
2642 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2643 if ((current_focus != NULL) &&
2644 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2645 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");