1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include "modest-marshal.h"
37 #include "modest-platform.h"
38 #include <modest-maemo-utils.h>
39 #include <modest-tny-msg.h>
40 #include <modest-msg-view-window.h>
41 #include <modest-attachments-view.h>
42 #include <modest-main-window-ui.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-runtime.h>
46 #include <modest-window-priv.h>
47 #include <modest-tny-folder.h>
48 #include <modest-text-utils.h>
49 #include <modest-account-mgr-helpers.h>
50 #include "modest-progress-bar-widget.h"
51 #include "modest-defs.h"
52 #include "modest-hildon-includes.h"
53 #include "modest-ui-dimming-manager.h"
54 #include <gdk/gdkkeysyms.h>
55 #include <modest-tny-account.h>
56 #include <modest-mime-part-view.h>
57 #include <modest-isearch-view.h>
60 #define DEFAULT_FOLDER "MyDocs/.documents"
62 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
63 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
64 static void modest_header_view_observer_init(
65 ModestHeaderViewObserverIface *iface_class);
66 static void modest_msg_view_window_finalize (GObject *obj);
67 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
69 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
70 ModestMsgViewWindow *obj);
71 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
72 ModestMsgViewWindow *obj);
74 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
75 static void modest_msg_view_window_set_zoom (ModestWindow *window,
77 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
78 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
79 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
80 static gboolean modest_msg_view_window_key_release_event (GtkWidget *window,
83 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
84 GdkEventWindowState *event,
86 static void modest_msg_view_window_scroll_up (ModestWindow *window);
87 static void modest_msg_view_window_scroll_down (ModestWindow *window);
88 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
90 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
91 gboolean show_toolbar);
93 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
95 ModestMsgViewWindow *window);
96 void modest_msg_view_window_on_row_changed(
97 GtkTreeModel *header_model,
100 ModestMsgViewWindow *window);
102 void modest_msg_view_window_on_row_deleted(
103 GtkTreeModel *header_model,
105 ModestMsgViewWindow *window);
107 void modest_msg_view_window_on_row_inserted(
108 GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 void modest_msg_view_window_on_row_reordered(
114 GtkTreeModel *header_model,
118 ModestMsgViewWindow *window);
120 void modest_msg_view_window_update_model_replaced(
121 ModestHeaderViewObserver *window,
123 const gchar *tny_folder_id);
125 static void cancel_progressbar (GtkToolButton *toolbutton,
126 ModestMsgViewWindow *self);
128 static void on_queue_changed (ModestMailOperationQueue *queue,
129 ModestMailOperation *mail_op,
130 ModestMailOperationQueueNotification type,
131 ModestMsgViewWindow *self);
133 static void on_account_removed (TnyAccountStore *account_store,
137 static void on_move_focus (ModestMsgViewWindow *window,
138 GtkDirectionType direction,
141 static void view_msg_cb (ModestMailOperation *mail_op,
146 static void set_toolbar_mode (ModestMsgViewWindow *self,
147 ModestToolBarModes mode);
149 static void update_window_title (ModestMsgViewWindow *window);
151 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
154 /* list my signals */
160 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
161 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
162 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
165 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
166 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
167 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
168 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
169 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
170 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
171 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
174 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
175 struct _ModestMsgViewWindowPrivate {
178 GtkWidget *main_scroll;
179 GtkWidget *find_toolbar;
182 /* Progress observers */
183 GtkWidget *progress_bar;
184 GSList *progress_widgets;
187 GtkWidget *progress_toolitem;
188 GtkWidget *cancel_toolitem;
189 GtkWidget *prev_toolitem;
190 GtkWidget *next_toolitem;
191 ModestToolBarModes current_toolbar_mode;
193 /* Optimized view enabled */
194 gboolean optimized_view;
196 /* Whether this was created via the *_new_for_search_result() function. */
197 gboolean is_search_result;
199 /* A reference to the @model of the header view
200 * to allow selecting previous/next messages,
201 * if the message is currently selected in the header view.
203 const gchar *header_folder_id;
204 GtkTreeModel *header_model;
205 GtkTreeRowReference *row_reference;
206 GtkTreeRowReference *next_row_reference;
208 gulong clipboard_change_handler;
209 gulong queue_change_handler;
210 gulong account_removed_handler;
211 gulong row_changed_handler;
212 gulong row_deleted_handler;
213 gulong row_inserted_handler;
214 gulong rows_reordered_handler;
217 GtkWidget *remove_attachment_banner;
219 guint progress_bar_timeout;
224 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
225 MODEST_TYPE_MSG_VIEW_WINDOW, \
226 ModestMsgViewWindowPrivate))
228 static GtkWindowClass *parent_class = NULL;
230 /* uncomment the following if you have defined any signals */
231 static guint signals[LAST_SIGNAL] = {0};
234 modest_msg_view_window_get_type (void)
236 static GType my_type = 0;
238 static const GTypeInfo my_info = {
239 sizeof(ModestMsgViewWindowClass),
240 NULL, /* base init */
241 NULL, /* base finalize */
242 (GClassInitFunc) modest_msg_view_window_class_init,
243 NULL, /* class finalize */
244 NULL, /* class data */
245 sizeof(ModestMsgViewWindow),
247 (GInstanceInitFunc) modest_msg_view_window_init,
250 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
251 "ModestMsgViewWindow",
254 static const GInterfaceInfo modest_header_view_observer_info =
256 (GInterfaceInitFunc) modest_header_view_observer_init,
257 NULL, /* interface_finalize */
258 NULL /* interface_data */
261 g_type_add_interface_static (my_type,
262 MODEST_TYPE_HEADER_VIEW_OBSERVER,
263 &modest_header_view_observer_info);
269 save_state (ModestWindow *self)
271 modest_widget_memory_save (modest_runtime_get_conf (),
273 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
278 restore_settings (ModestMsgViewWindow *self)
280 modest_widget_memory_restore (modest_runtime_get_conf (),
282 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
286 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
288 GObjectClass *gobject_class;
289 ModestWindowClass *modest_window_class;
290 gobject_class = (GObjectClass*) klass;
291 modest_window_class = (ModestWindowClass *) klass;
293 parent_class = g_type_class_peek_parent (klass);
294 gobject_class->finalize = modest_msg_view_window_finalize;
296 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
297 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
298 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
299 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
300 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
301 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
303 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
305 modest_window_class->save_state_func = save_state;
307 signals[MSG_CHANGED_SIGNAL] =
308 g_signal_new ("msg-changed",
309 G_TYPE_FROM_CLASS (gobject_class),
311 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
313 modest_marshal_VOID__POINTER_POINTER,
314 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
317 static void modest_header_view_observer_init(
318 ModestHeaderViewObserverIface *iface_class)
320 iface_class->update_func = modest_msg_view_window_update_model_replaced;
324 modest_msg_view_window_init (ModestMsgViewWindow *obj)
326 ModestMsgViewWindowPrivate *priv;
327 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
329 priv->is_search_result = FALSE;
331 priv->msg_view = NULL;
332 priv->header_model = NULL;
333 priv->header_folder_id = NULL;
334 priv->clipboard_change_handler = 0;
335 priv->queue_change_handler = 0;
336 priv->account_removed_handler = 0;
337 priv->row_changed_handler = 0;
338 priv->row_deleted_handler = 0;
339 priv->row_inserted_handler = 0;
340 priv->rows_reordered_handler = 0;
341 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
343 priv->optimized_view = FALSE;
344 priv->progress_bar_timeout = 0;
345 priv->purge_timeout = 0;
346 priv->remove_attachment_banner = NULL;
347 priv->msg_uid = NULL;
349 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
350 GTK_WINDOW(obj),"applications_email_viewer");
355 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
357 ModestMsgViewWindowPrivate *priv = NULL;
359 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
361 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
363 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
365 if (priv->progress_bar_timeout > 0) {
366 g_source_remove (priv->progress_bar_timeout);
367 priv->progress_bar_timeout = 0;
374 set_toolbar_mode (ModestMsgViewWindow *self,
375 ModestToolBarModes mode)
377 ModestWindowPrivate *parent_priv;
378 ModestMsgViewWindowPrivate *priv;
379 /* GtkWidget *widget = NULL; */
381 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
383 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
384 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
386 /* Sets current toolbar mode */
387 priv->current_toolbar_mode = mode;
389 /* Update toolbar dimming state */
390 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
393 case TOOLBAR_MODE_NORMAL:
394 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
395 /* gtk_action_set_sensitive (widget, TRUE); */
396 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
397 /* gtk_action_set_sensitive (widget, TRUE); */
398 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
399 /* gtk_action_set_sensitive (widget, TRUE); */
400 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
401 /* gtk_action_set_sensitive (widget, TRUE); */
403 if (priv->prev_toolitem)
404 gtk_widget_show (priv->prev_toolitem);
406 if (priv->next_toolitem)
407 gtk_widget_show (priv->next_toolitem);
409 if (priv->progress_toolitem)
410 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
411 if (priv->progress_bar)
412 gtk_widget_hide (priv->progress_bar);
414 if (priv->cancel_toolitem)
415 gtk_widget_hide (priv->cancel_toolitem);
417 /* Hide toolbar if optimized view is enabled */
418 if (priv->optimized_view) {
419 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
420 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
424 case TOOLBAR_MODE_TRANSFER:
425 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
426 /* gtk_action_set_sensitive (widget, FALSE); */
427 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
428 /* gtk_action_set_sensitive (widget, FALSE); */
429 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
430 /* gtk_action_set_sensitive (widget, FALSE); */
431 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
432 /* gtk_action_set_sensitive (widget, FALSE); */
434 if (priv->prev_toolitem)
435 gtk_widget_hide (priv->prev_toolitem);
437 if (priv->next_toolitem)
438 gtk_widget_hide (priv->next_toolitem);
440 if (priv->progress_toolitem)
441 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
442 if (priv->progress_bar)
443 gtk_widget_show (priv->progress_bar);
445 if (priv->cancel_toolitem)
446 gtk_widget_show (priv->cancel_toolitem);
448 /* Show toolbar if it's hiden (optimized view ) */
449 if (priv->optimized_view) {
450 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
451 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
456 g_return_if_reached ();
463 menubar_to_menu (GtkUIManager *ui_manager)
465 GtkWidget *main_menu;
467 GList *iter, *children;
469 /* Create new main menu */
470 main_menu = gtk_menu_new();
472 /* Get the menubar from the UI manager */
473 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
475 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
479 menu = GTK_WIDGET (iter->data);
480 gtk_widget_reparent(menu, main_menu);
482 iter = g_list_next (iter);
484 g_list_free (children);
490 init_window (ModestMsgViewWindow *obj)
492 GtkWidget *main_vbox;
493 ModestMsgViewWindowPrivate *priv;
494 ModestWindowPrivate *parent_priv;
496 GtkAction *action = NULL;
498 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
499 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
501 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
502 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
503 main_vbox = gtk_vbox_new (FALSE, 6);
506 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
507 conf = modest_runtime_get_conf ();
508 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
509 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
510 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
511 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
512 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
513 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
514 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
515 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
516 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
517 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
519 #ifdef MODEST_USE_MOZEMBED
520 priv->main_scroll = priv->msg_view;
521 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
523 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
524 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
526 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
527 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
528 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
530 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
531 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
533 priv->find_toolbar = hildon_find_toolbar_new (NULL);
534 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
535 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
536 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
537 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
539 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
540 gtk_widget_show_all (GTK_WIDGET(main_vbox));
544 modest_msg_view_window_disconnect_signals (ModestWindow *self)
546 ModestMsgViewWindowPrivate *priv;
547 ModestHeaderView *header_view = NULL;
548 ModestWindow *main_window = NULL;
550 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
552 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
553 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
554 priv->clipboard_change_handler))
555 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
556 priv->clipboard_change_handler);
558 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
559 priv->queue_change_handler))
560 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
561 priv->queue_change_handler);
563 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
564 priv->account_removed_handler))
565 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
566 priv->account_removed_handler);
568 if (priv->header_model) {
569 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
570 priv->row_changed_handler))
571 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
572 priv->row_changed_handler);
574 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
575 priv->row_deleted_handler))
576 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
577 priv->row_deleted_handler);
579 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
580 priv->row_inserted_handler))
581 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
582 priv->row_inserted_handler);
584 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
585 priv->rows_reordered_handler))
586 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
587 priv->rows_reordered_handler);
590 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
591 FALSE); /* don't create */
595 header_view = MODEST_HEADER_VIEW(
596 modest_main_window_get_child_widget(
597 MODEST_MAIN_WINDOW(main_window),
598 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
599 if (header_view == NULL)
602 modest_header_view_remove_observer(header_view,
603 MODEST_HEADER_VIEW_OBSERVER(self));
607 modest_msg_view_window_finalize (GObject *obj)
609 ModestMsgViewWindowPrivate *priv;
611 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
613 /* Sanity check: shouldn't be needed, the window mgr should
614 call this function before */
615 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
617 if (priv->header_model != NULL) {
618 g_object_unref (priv->header_model);
619 priv->header_model = NULL;
622 if (priv->progress_bar_timeout > 0) {
623 g_source_remove (priv->progress_bar_timeout);
624 priv->progress_bar_timeout = 0;
627 if (priv->remove_attachment_banner) {
628 gtk_widget_destroy (priv->remove_attachment_banner);
629 g_object_unref (priv->remove_attachment_banner);
630 priv->remove_attachment_banner = NULL;
633 if (priv->purge_timeout > 0) {
634 g_source_remove (priv->purge_timeout);
635 priv->purge_timeout = 0;
638 if (priv->row_reference) {
639 gtk_tree_row_reference_free (priv->row_reference);
640 priv->row_reference = NULL;
643 if (priv->next_row_reference) {
644 gtk_tree_row_reference_free (priv->next_row_reference);
645 priv->next_row_reference = NULL;
649 g_free (priv->msg_uid);
650 priv->msg_uid = NULL;
653 G_OBJECT_CLASS(parent_class)->finalize (obj);
657 select_next_valid_row (GtkTreeModel *model,
658 GtkTreeRowReference **row_reference,
661 GtkTreeIter tmp_iter;
662 GtkTreePath *path, *next;
663 gboolean retval = FALSE;
665 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
667 path = gtk_tree_row_reference_get_path (*row_reference);
668 gtk_tree_model_get_iter (model, &tmp_iter, path);
669 gtk_tree_row_reference_free (*row_reference);
670 *row_reference = NULL;
672 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
673 next = gtk_tree_model_get_path (model, &tmp_iter);
674 *row_reference = gtk_tree_row_reference_new (model, next);
676 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
677 next = gtk_tree_model_get_path (model, &tmp_iter);
679 /* Ensure that we are not selecting the same */
680 if (gtk_tree_path_compare (path, next) != 0) {
681 *row_reference = gtk_tree_row_reference_new (model, next);
687 gtk_tree_path_free (path);
692 /* TODO: This should be in _init(), with the parameters as properties. */
694 modest_msg_view_window_construct (ModestMsgViewWindow *self,
695 const gchar *modest_account_name,
696 const gchar *msg_uid)
699 ModestMsgViewWindowPrivate *priv = NULL;
700 ModestWindowPrivate *parent_priv = NULL;
701 ModestDimmingRulesGroup *menu_rules_group = NULL;
702 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
703 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
704 GtkActionGroup *action_group = NULL;
705 GError *error = NULL;
706 GdkPixbuf *window_icon;
708 obj = G_OBJECT (self);
709 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
710 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
712 priv->msg_uid = g_strdup (msg_uid);
714 parent_priv->ui_manager = gtk_ui_manager_new();
715 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
717 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
718 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
720 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
721 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
722 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
724 /* Add common actions */
725 gtk_action_group_add_actions (action_group,
726 modest_action_entries,
727 G_N_ELEMENTS (modest_action_entries),
729 gtk_action_group_add_toggle_actions (action_group,
730 modest_toggle_action_entries,
731 G_N_ELEMENTS (modest_toggle_action_entries),
733 gtk_action_group_add_toggle_actions (action_group,
734 msg_view_toggle_action_entries,
735 G_N_ELEMENTS (msg_view_toggle_action_entries),
737 gtk_action_group_add_radio_actions (action_group,
738 msg_view_zoom_action_entries,
739 G_N_ELEMENTS (msg_view_zoom_action_entries),
741 G_CALLBACK (modest_ui_actions_on_change_zoom),
744 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
745 g_object_unref (action_group);
747 /* Load the UI definition */
748 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
751 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
752 g_error_free (error);
757 /* Add common dimming rules */
758 modest_dimming_rules_group_add_rules (menu_rules_group,
759 modest_msg_view_menu_dimming_entries,
760 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
761 MODEST_WINDOW (self));
762 modest_dimming_rules_group_add_rules (toolbar_rules_group,
763 modest_msg_view_toolbar_dimming_entries,
764 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
765 MODEST_WINDOW (self));
766 modest_dimming_rules_group_add_rules (clipboard_rules_group,
767 modest_msg_view_clipboard_dimming_entries,
768 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
769 MODEST_WINDOW (self));
771 /* Insert dimming rules group for this window */
772 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
773 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
774 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
775 g_object_unref (menu_rules_group);
776 g_object_unref (toolbar_rules_group);
777 g_object_unref (clipboard_rules_group);
779 /* Add accelerators */
780 gtk_window_add_accel_group (GTK_WINDOW (obj),
781 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
784 init_window (MODEST_MSG_VIEW_WINDOW(obj));
785 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
787 /* Set window icon */
788 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
790 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
791 g_object_unref (window_icon);
794 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
796 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
797 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
798 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
799 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
800 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
801 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
802 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
803 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
804 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
805 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
807 g_signal_connect (G_OBJECT (obj), "key-release-event",
808 G_CALLBACK (modest_msg_view_window_key_release_event),
811 g_signal_connect (G_OBJECT (obj), "window-state-event",
812 G_CALLBACK (modest_msg_view_window_window_state_event),
815 g_signal_connect (G_OBJECT (obj), "move-focus",
816 G_CALLBACK (on_move_focus), obj);
818 /* Mail Operation Queue */
819 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
821 G_CALLBACK (on_queue_changed),
824 /* Account manager */
825 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
827 G_CALLBACK(on_account_removed),
830 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
832 priv->last_search = NULL;
834 /* Init the clipboard actions dim status */
835 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
837 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
839 /* Check toolbar dimming rules */
840 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
841 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
845 /* FIXME: parameter checks */
847 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
848 const gchar *modest_account_name,
849 const gchar *msg_uid,
851 GtkTreeRowReference *row_reference)
853 ModestMsgViewWindow *window = NULL;
854 ModestMsgViewWindowPrivate *priv = NULL;
855 TnyFolder *header_folder = NULL;
856 ModestHeaderView *header_view = NULL;
857 ModestWindow *main_window = NULL;
859 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
860 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
862 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
864 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
866 /* Remember the message list's TreeModel so we can detect changes
867 * and change the list selection when necessary: */
869 main_window = modest_window_mgr_get_main_window(
870 modest_runtime_get_window_mgr(), FALSE); /* don't create */
872 g_warning ("%s: BUG: no main window", __FUNCTION__);
876 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
877 MODEST_MAIN_WINDOW(main_window),
878 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
879 if (header_view != NULL){
880 header_folder = modest_header_view_get_folder(header_view);
881 g_assert(header_folder != NULL);
882 priv->header_folder_id = tny_folder_get_id(header_folder);
883 g_assert(priv->header_folder_id != NULL);
884 g_object_unref(header_folder);
887 priv->header_model = g_object_ref(model);
888 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
889 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
890 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
892 priv->row_changed_handler = g_signal_connect(
893 GTK_TREE_MODEL(model), "row-changed",
894 G_CALLBACK(modest_msg_view_window_on_row_changed),
896 priv->row_deleted_handler = g_signal_connect(
897 GTK_TREE_MODEL(model), "row-deleted",
898 G_CALLBACK(modest_msg_view_window_on_row_deleted),
900 priv->row_inserted_handler = g_signal_connect (
901 GTK_TREE_MODEL(model), "row-inserted",
902 G_CALLBACK(modest_msg_view_window_on_row_inserted),
904 priv->rows_reordered_handler = g_signal_connect(
905 GTK_TREE_MODEL(model), "rows-reordered",
906 G_CALLBACK(modest_msg_view_window_on_row_reordered),
909 if (header_view != NULL){
910 modest_header_view_add_observer(header_view,
911 MODEST_HEADER_VIEW_OBSERVER(window));
914 gtk_widget_show_all (GTK_WIDGET (window));
916 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
917 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
919 modest_msg_view_window_update_priority (window);
921 /* Check toolbar dimming rules */
922 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
924 return MODEST_WINDOW(window);
928 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
929 const gchar *modest_account_name,
930 const gchar *msg_uid)
932 ModestMsgViewWindow *window = NULL;
933 ModestMsgViewWindowPrivate *priv = NULL;
935 window = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
936 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
937 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
939 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
941 /* Remember that this is a search result,
942 * so we can disable some UI appropriately: */
943 priv->is_search_result = TRUE;
945 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
947 return MODEST_WINDOW(window);
951 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
952 const gchar *modest_account_name,
953 const gchar *msg_uid)
956 ModestMsgViewWindowPrivate *priv;
957 g_return_val_if_fail (msg, NULL);
959 obj = g_object_new(MODEST_TYPE_MSG_VIEW_WINDOW, NULL);
960 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
961 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
962 modest_account_name, msg_uid);
964 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
966 return MODEST_WINDOW(obj);
969 void modest_msg_view_window_on_row_changed(
970 GtkTreeModel *header_model,
973 ModestMsgViewWindow *window){
974 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
977 void modest_msg_view_window_on_row_deleted(
978 GtkTreeModel *header_model,
980 ModestMsgViewWindow *window){
981 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
984 /* On insertions we check if the folder still has the message we are
985 * showing or do not. If do not, we do nothing. Which means we are still
986 * not attached to any header folder and thus next/prev buttons are
987 * still dimmed. Once the message that is shown by msg-view is found, the
988 * new model of header-view will be attached and the references will be set.
989 * On each further insertions dimming rules will be checked. However
990 * this requires extra CPU time at least works.
991 * (An message might be deleted from TnyFolder and thus will not be
992 * inserted into the model again for example if it is removed by the
993 * imap server and the header view is refreshed.)
995 void modest_msg_view_window_on_row_inserted(
996 GtkTreeModel *new_model,
997 GtkTreePath *tree_path,
998 GtkTreeIter *tree_iter,
999 ModestMsgViewWindow *window){
1000 ModestMsgViewWindowPrivate *priv = NULL;
1001 TnyHeader *header = NULL;
1004 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1006 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1008 /* If we already has a model attached then the message shown by
1009 * msg-view is in it, and thus we do not need any actions but
1010 * to check the dimming rules.*/
1011 if(priv->header_model != NULL){
1012 gtk_tree_row_reference_free(priv->next_row_reference);
1013 priv->next_row_reference = gtk_tree_row_reference_copy(
1014 priv->row_reference);
1015 select_next_valid_row (priv->header_model,
1016 &(priv->next_row_reference), FALSE);
1017 modest_ui_actions_check_toolbar_dimming_rules (
1018 MODEST_WINDOW (window));
1022 /* Check if the newly inserted message is the same we are actually
1023 * showing. IF not, we should remain detached from the header model
1024 * and thus prev and next toolbarbuttons should remain dimmed. */
1025 gtk_tree_model_get (new_model, tree_iter,
1026 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1027 uid = modest_tny_folder_get_header_unique_id(header);
1028 if(!g_str_equal(priv->msg_uid, uid)){
1034 /* Setup row_reference for the actual msg. */
1035 priv->row_reference = gtk_tree_row_reference_new(
1036 new_model, tree_path);
1037 if(priv->row_reference == NULL){
1038 g_warning("No reference for msg header item.");
1042 /* Attach new_model and connect some callback to it to become able
1043 * to detect changes in header-view. */
1044 priv->header_model = g_object_ref(new_model);
1045 g_signal_connect (new_model, "row-changed",
1046 G_CALLBACK (modest_msg_view_window_on_row_changed),
1048 g_signal_connect (new_model, "row-deleted",
1049 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1051 g_signal_connect (new_model, "rows-reordered",
1052 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1055 /* Now set up next_row_reference. */
1056 priv->next_row_reference = gtk_tree_row_reference_copy(
1057 priv->row_reference);
1058 select_next_valid_row (priv->header_model,
1059 &(priv->next_row_reference), FALSE);
1061 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1064 void modest_msg_view_window_on_row_reordered(
1065 GtkTreeModel *header_model,
1069 ModestMsgViewWindow *window){
1070 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1073 /* The modest_msg_view_window_update_model_replaced implements update
1074 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1075 * actually belongs to the header-view is the same as the TnyFolder of
1076 * the message of msg-view or not. If they are different, there is
1077 * nothing to do. If they are the same, then the model has replaced and
1078 * the reference in msg-view shall be replaced from the old model to
1079 * the new model. In this case the view will be detached from it's
1080 * header folder. From this point the next/prev buttons are dimmed.
1082 void modest_msg_view_window_update_model_replaced(
1083 ModestHeaderViewObserver *observer,
1084 GtkTreeModel *model,
1085 const gchar *tny_folder_id){
1086 ModestMsgViewWindowPrivate *priv = NULL;
1087 ModestMsgViewWindow *window = NULL;
1089 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1090 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1092 window = MODEST_MSG_VIEW_WINDOW(observer);
1093 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1095 /* If there is an other folder in the header-view then we do
1096 * not care about it's model (msg list). Else if the
1097 * header-view shows the folder the msg shown by us is in, we
1098 * shall replace our model reference and make some check. */
1099 if(tny_folder_id == NULL ||
1100 !g_str_equal(tny_folder_id, priv->header_folder_id))
1103 /* Model is changed(replaced), so we should forget the old
1104 * one. Because there might be other references and there
1105 * might be some change on the model even if we unreferenced
1106 * it, we need to disconnect our signals here. */
1107 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1108 priv->row_changed_handler))
1109 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1110 priv->row_changed_handler);
1111 priv->row_changed_handler = 0;
1112 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1113 priv->row_deleted_handler))
1114 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1115 priv->row_deleted_handler);
1116 priv->row_deleted_handler = 0;
1117 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1118 priv->row_inserted_handler))
1119 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1120 priv->row_inserted_handler);
1121 priv->row_inserted_handler = 0;
1122 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1123 priv->rows_reordered_handler))
1124 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1125 priv->rows_reordered_handler);
1126 priv->rows_reordered_handler = 0;
1127 g_object_unref(priv->header_model);
1128 priv->header_model = NULL;
1129 g_object_unref(priv->row_reference);
1130 priv->row_reference = NULL;
1131 g_object_unref(priv->next_row_reference);
1132 priv->next_row_reference = NULL;
1134 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1136 if(tny_folder_id == NULL)
1139 g_assert(model != NULL);
1141 /* Also we must connect to the new model for row insertions.
1142 * Only for insertions now. We will need other ones only after
1143 * the msg is show by msg-view is added to the new model. */
1144 priv->row_inserted_handler = g_signal_connect (
1145 model, "row-inserted",
1146 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1151 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1153 ModestMsgViewWindowPrivate *priv= NULL;
1155 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1156 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1158 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1162 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1164 ModestMsgViewWindowPrivate *priv= NULL;
1166 TnyHeader *header = NULL;
1167 GtkTreePath *path = NULL;
1170 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1171 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1173 /* If the message was not obtained from a treemodel,
1174 * for instance if it was opened directly by the search UI:
1176 if (priv->header_model == NULL) {
1177 msg = modest_msg_view_window_get_message (self);
1179 header = tny_msg_get_header (msg);
1180 g_object_unref (msg);
1185 /* Get iter of the currently selected message in the header view: */
1186 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1187 * instead of sometimes retrieving it from the header view?
1188 * Then we wouldn't be dependent on the message actually still being selected
1189 * in the header view. murrayc. */
1190 if (!gtk_tree_row_reference_valid (priv->row_reference))
1192 path = gtk_tree_row_reference_get_path (priv->row_reference);
1193 g_return_val_if_fail (path != NULL, NULL);
1194 gtk_tree_model_get_iter (priv->header_model,
1198 /* Get current message header */
1199 gtk_tree_model_get (priv->header_model, &iter,
1200 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1203 gtk_tree_path_free (path);
1208 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1210 ModestMsgView *msg_view;
1211 ModestMsgViewWindowPrivate *priv;
1213 g_return_val_if_fail (self, NULL);
1215 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1217 msg_view = MODEST_MSG_VIEW (priv->msg_view);
1219 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1223 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1225 ModestMsgViewWindowPrivate *priv;
1227 g_return_val_if_fail (self, NULL);
1229 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1231 return (const gchar*) priv->msg_uid;
1235 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1238 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1239 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1240 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1244 is_active = gtk_toggle_action_get_active (toggle);
1247 gtk_widget_show (priv->find_toolbar);
1248 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1250 gtk_widget_hide (priv->find_toolbar);
1253 /* update the toggle buttons status */
1254 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1255 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1256 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1257 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1262 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1263 ModestMsgViewWindow *obj)
1265 GtkToggleAction *toggle;
1266 ModestWindowPrivate *parent_priv;
1267 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1269 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1270 gtk_toggle_action_set_active (toggle, FALSE);
1274 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1275 ModestMsgViewWindow *obj)
1277 gchar *current_search;
1278 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1280 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1281 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1285 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1287 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1288 g_free (current_search);
1289 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1293 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1295 g_free (priv->last_search);
1296 priv->last_search = g_strdup (current_search);
1297 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1300 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1301 g_free (priv->last_search);
1302 priv->last_search = NULL;
1304 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1307 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1308 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1309 g_free (priv->last_search);
1310 priv->last_search = NULL;
1312 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1316 g_free (current_search);
1321 modest_msg_view_window_set_zoom (ModestWindow *window,
1324 ModestMsgViewWindowPrivate *priv;
1325 ModestWindowPrivate *parent_priv;
1326 GtkAction *action = NULL;
1327 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1329 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1331 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1332 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1333 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1335 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1336 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1338 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1342 modest_msg_view_window_get_zoom (ModestWindow *window)
1344 ModestMsgViewWindowPrivate *priv;
1346 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1348 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1349 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1353 modest_msg_view_window_zoom_plus (ModestWindow *window)
1355 ModestWindowPrivate *parent_priv;
1356 GtkRadioAction *zoom_radio_action;
1357 GSList *group, *node;
1359 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1360 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1361 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1363 group = gtk_radio_action_get_group (zoom_radio_action);
1365 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1366 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1370 for (node = group; node != NULL; node = g_slist_next (node)) {
1371 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1372 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1380 modest_msg_view_window_zoom_minus (ModestWindow *window)
1382 ModestWindowPrivate *parent_priv;
1383 GtkRadioAction *zoom_radio_action;
1384 GSList *group, *node;
1386 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1387 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1388 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1390 group = gtk_radio_action_get_group (zoom_radio_action);
1392 for (node = group; node != NULL; node = g_slist_next (node)) {
1393 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1394 if (node->next != NULL) {
1395 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1398 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1408 modest_msg_view_window_key_release_event (GtkWidget *window,
1412 if (event->type == GDK_KEY_RELEASE) {
1413 switch (event->keyval) {
1415 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1419 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1432 modest_msg_view_window_scroll_up (ModestWindow *window)
1434 ModestMsgViewWindowPrivate *priv;
1435 gboolean return_value;
1437 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1438 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1442 modest_msg_view_window_scroll_down (ModestWindow *window)
1444 ModestMsgViewWindowPrivate *priv;
1445 gboolean return_value;
1447 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1448 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1452 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1455 ModestMsgViewWindowPrivate *priv;
1456 GtkTreeIter tmp_iter;
1457 gboolean is_last_selected;
1459 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1460 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1462 /*if no model (so no rows at all), then virtually we are the last*/
1463 if (!priv->header_model)
1466 path = gtk_tree_row_reference_get_path (priv->row_reference);
1470 is_last_selected = TRUE;
1471 while (is_last_selected) {
1473 gtk_tree_path_next (path);
1474 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1476 gtk_tree_model_get (priv->header_model, &tmp_iter,
1477 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1479 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1480 is_last_selected = FALSE;
1482 gtk_tree_path_free (path);
1483 return is_last_selected;
1487 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1489 ModestMsgViewWindowPrivate *priv;
1491 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1492 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1494 return priv->header_model != NULL;
1498 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1500 ModestMsgViewWindowPrivate *priv;
1502 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1503 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1505 return priv->is_search_result;
1509 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1512 ModestMsgViewWindowPrivate *priv;
1513 gboolean is_first_selected;
1514 GtkTreeIter tmp_iter;
1515 /* gchar * path_string;*/
1517 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1518 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1520 /*if no model (so no rows at all), then virtually we are the first*/
1521 if (!priv->header_model)
1524 path = gtk_tree_row_reference_get_path (priv->row_reference);
1528 /* path_string = gtk_tree_path_to_string (path);
1529 is_first_selected = strcmp (path_string, "0");
1531 g_free (path_string);
1532 gtk_tree_path_free (path);
1534 return is_first_selected;*/
1536 is_first_selected = TRUE;
1537 while (is_first_selected) {
1539 if(!gtk_tree_path_prev (path))
1541 /* Here the 'if' is needless for logic, but let make sure
1542 * iter is valid for gtk_tree_model_get. */
1543 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1545 gtk_tree_model_get (priv->header_model, &tmp_iter,
1546 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1548 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1549 is_first_selected = FALSE;
1551 gtk_tree_path_free (path);
1552 return is_first_selected;
1556 * Reads the message whose summary item is @header. It takes care of
1557 * several things, among others:
1559 * If the message was not previously downloaded then ask the user
1560 * before downloading. If there is no connection launch the connection
1561 * dialog. Update toolbar dimming rules.
1563 * Returns: TRUE if the mail operation was started, otherwise if the
1564 * user do not want to download the message, or if the user do not
1565 * want to connect, then the operation is not issued
1568 message_reader (ModestMsgViewWindow *window,
1569 ModestMsgViewWindowPrivate *priv,
1571 GtkTreeRowReference *row_reference)
1573 ModestMailOperation *mail_op = NULL;
1574 ModestMailOperationTypeOperation op_type;
1575 gboolean already_showing = FALSE;
1576 ModestWindow *msg_window = NULL;
1577 ModestWindowMgr *mgr;
1579 g_return_val_if_fail (row_reference != NULL, FALSE);
1581 mgr = modest_runtime_get_window_mgr ();
1582 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1583 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1586 gtk_window_present (GTK_WINDOW (msg_window));
1587 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1591 /* Msg download completed */
1592 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1593 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1595 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1597 /* Ask the user if he wants to download the message if
1599 if (!tny_device_is_online (modest_runtime_get_device())) {
1600 TnyFolder *folder = NULL;
1601 GtkResponseType response;
1603 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1604 _("mcen_nc_get_msg"));
1605 if (response == GTK_RESPONSE_CANCEL)
1608 /* Offer the connection dialog if necessary */
1609 folder = tny_header_get_folder (header);
1611 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1612 TNY_FOLDER_STORE (folder))) {
1613 g_object_unref (folder);
1616 g_object_unref (folder);
1621 /* New mail operation */
1622 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1623 modest_ui_actions_get_msgs_full_error_handler,
1626 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1627 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1628 g_object_unref (mail_op);
1630 /* Update toolbar dimming rules */
1631 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1637 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1639 ModestMsgViewWindowPrivate *priv;
1640 GtkTreePath *path= NULL;
1641 GtkTreeIter tmp_iter;
1643 gboolean retval = TRUE;
1644 GtkTreeRowReference *row_reference = NULL;
1646 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1647 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1649 /* Update the next row reference if it's not valid. This could
1650 happen if for example the header which it was pointing to,
1651 was deleted. The best place to do it is in the row-deleted
1652 handler but the tinymail model do not work like the glib
1653 tree models and reports the deletion when the row is still
1655 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1656 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1657 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1658 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1661 if (priv->next_row_reference)
1662 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1666 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1668 gtk_tree_model_get_iter (priv->header_model,
1671 gtk_tree_path_free (path);
1673 gtk_tree_model_get (priv->header_model, &tmp_iter,
1674 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1677 /* Read the message & show it */
1678 if (!message_reader (window, priv, header, row_reference)) {
1680 gtk_tree_row_reference_free (row_reference);
1684 g_object_unref (header);
1690 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1692 ModestMsgViewWindowPrivate *priv = NULL;
1693 TnyHeader *header = NULL;
1695 GtkTreePath *path = NULL;
1696 GtkTreeRowReference *row_reference = NULL;
1698 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1699 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1701 /* Check that the model is not empty */
1702 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1705 /* Get the header */
1706 gtk_tree_model_get (priv->header_model,
1708 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1710 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1711 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1712 g_object_unref (header);
1713 return modest_msg_view_window_select_next_message (self);
1716 path = gtk_tree_model_get_path (priv->header_model, &iter);
1717 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1718 gtk_tree_path_free (path);
1720 /* Read the message & show it */
1721 message_reader (self, priv, header, row_reference);
1724 g_object_unref (header);
1730 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1732 ModestMsgViewWindowPrivate *priv = NULL;
1734 GtkTreeRowReference *row_reference = NULL;
1736 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1737 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1739 /* Return inmediatly if there is no header model */
1740 if (!priv->header_model)
1743 path = gtk_tree_row_reference_get_path (priv->row_reference);
1744 while (gtk_tree_path_prev (path)) {
1748 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1749 gtk_tree_model_get (priv->header_model, &iter,
1750 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1754 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1755 g_object_unref (header);
1759 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1760 /* Read the message & show it */
1761 if (!message_reader (window, priv, header, row_reference)) {
1762 gtk_tree_row_reference_free (row_reference);
1763 g_object_unref (header);
1767 gtk_tree_path_free (path);
1768 g_object_unref (header);
1773 gtk_tree_path_free (path);
1778 view_msg_cb (ModestMailOperation *mail_op,
1783 ModestMsgViewWindow *self = NULL;
1784 ModestMsgViewWindowPrivate *priv = NULL;
1785 GtkTreeRowReference *row_reference = NULL;
1787 /* If there was any error */
1788 row_reference = (GtkTreeRowReference *) user_data;
1789 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1790 gtk_tree_row_reference_free (row_reference);
1794 /* Get the window */
1795 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1796 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1797 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1799 /* Update the row reference */
1800 gtk_tree_row_reference_free (priv->row_reference);
1801 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1802 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1803 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1804 gtk_tree_row_reference_free (row_reference);
1806 /* Mark header as read */
1807 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1808 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1810 /* Set new message */
1811 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1812 modest_msg_view_window_update_priority (self);
1813 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1814 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1816 /* Set the new message uid of the window */
1817 if (priv->msg_uid) {
1818 g_free (priv->msg_uid);
1819 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1822 /* Notify the observers */
1823 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1824 0, priv->header_model, priv->row_reference);
1826 /* Free new references */
1827 g_object_unref (self);
1831 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1833 ModestMsgViewWindowPrivate *priv;
1835 TnyFolderType folder_type;
1837 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1839 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1841 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1845 folder = tny_msg_get_folder (msg);
1847 folder_type = tny_folder_get_folder_type (folder);
1848 g_object_unref (folder);
1850 g_object_unref (msg);
1858 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1860 ModestMsgViewWindowPrivate *priv;
1861 TnyHeaderFlags flags = 0;
1863 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1865 if (priv->header_model) {
1868 GtkTreePath *path = NULL;
1870 path = gtk_tree_row_reference_get_path (priv->row_reference);
1871 g_return_if_fail (path != NULL);
1872 gtk_tree_model_get_iter (priv->header_model,
1874 gtk_tree_row_reference_get_path (priv->row_reference));
1876 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1878 flags = tny_header_get_flags (header);
1879 gtk_tree_path_free (path);
1882 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1887 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1889 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1890 ModestWindowPrivate *parent_priv;
1891 ModestWindowMgr *mgr;
1892 gboolean is_fullscreen;
1893 GtkAction *fs_toggle_action;
1896 mgr = modest_runtime_get_window_mgr ();
1897 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1899 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1901 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1902 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1903 if (is_fullscreen != active) {
1904 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1913 set_homogeneous (GtkWidget *widget,
1916 if (GTK_IS_TOOL_ITEM (widget)) {
1917 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1918 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1923 modest_msg_view_window_show_toolbar (ModestWindow *self,
1924 gboolean show_toolbar)
1926 ModestMsgViewWindowPrivate *priv = NULL;
1927 ModestWindowPrivate *parent_priv;
1928 GtkWidget *reply_button = NULL, *menu = NULL;
1929 GtkWidget *placeholder = NULL;
1931 const gchar *action_name;
1934 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1935 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1937 /* Set optimized view status */
1938 priv->optimized_view = !show_toolbar;
1940 if (!parent_priv->toolbar) {
1941 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1943 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1945 /* Set homogeneous toolbar */
1946 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1947 set_homogeneous, NULL);
1949 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1950 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1951 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1952 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1953 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1954 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1955 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1956 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1958 /* Add ProgressBar (Transfer toolbar) */
1959 priv->progress_bar = modest_progress_bar_widget_new ();
1960 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1961 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1962 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1963 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1964 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1966 /* Connect cancel 'clicked' signal to abort progress mode */
1967 g_signal_connect(priv->cancel_toolitem, "clicked",
1968 G_CALLBACK(cancel_progressbar),
1971 /* Add it to the observers list */
1972 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1975 hildon_window_add_toolbar (HILDON_WINDOW (self),
1976 GTK_TOOLBAR (parent_priv->toolbar));
1979 /* Set reply button tap and hold menu */
1980 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1981 "/ToolBar/ToolbarMessageReply");
1982 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1983 "/ToolbarReplyCSM");
1984 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1988 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1989 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1990 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1992 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1993 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1996 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1997 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2000 /* Update also the actions (to update the toggles in the
2001 menus), we have to do it manually because some other window
2002 of the same time could have changed it (remember that the
2003 toolbar fullscreen mode is shared by all the windows of the
2005 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2006 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2008 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2010 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2011 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2016 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2018 ModestMsgViewWindow *window)
2020 if (!GTK_WIDGET_VISIBLE (window))
2023 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2027 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2029 ModestMsgViewWindowPrivate *priv;
2031 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2032 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2034 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2038 cancel_progressbar (GtkToolButton *toolbutton,
2039 ModestMsgViewWindow *self)
2042 ModestMsgViewWindowPrivate *priv;
2044 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2046 /* Get operation observers and cancel its current operation */
2047 tmp = priv->progress_widgets;
2049 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2050 tmp=g_slist_next(tmp);
2054 observers_empty (ModestMsgViewWindow *self)
2057 ModestMsgViewWindowPrivate *priv;
2058 gboolean is_empty = TRUE;
2059 guint pending_ops = 0;
2061 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2062 tmp = priv->progress_widgets;
2064 /* Check all observers */
2065 while (tmp && is_empty) {
2066 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2067 is_empty = pending_ops == 0;
2069 tmp = g_slist_next(tmp);
2076 on_account_removed (TnyAccountStore *account_store,
2077 TnyAccount *account,
2080 /* Do nothing if it's a transport account, because we only
2081 show the messages of a store account */
2082 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2083 const gchar *parent_acc = NULL;
2084 const gchar *our_acc = NULL;
2086 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2087 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2089 /* Close this window if I'm showing a message of the removed account */
2090 if (strcmp (parent_acc, our_acc) == 0)
2091 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2096 on_queue_changed (ModestMailOperationQueue *queue,
2097 ModestMailOperation *mail_op,
2098 ModestMailOperationQueueNotification type,
2099 ModestMsgViewWindow *self)
2102 ModestMsgViewWindowPrivate *priv;
2103 ModestMailOperationTypeOperation op_type;
2104 ModestToolBarModes mode;
2106 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2107 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2109 /* If this operations was created by another window, do nothing */
2110 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2113 /* Get toolbar mode from operation id*/
2114 op_type = modest_mail_operation_get_type_operation (mail_op);
2116 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2117 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2118 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2119 mode = TOOLBAR_MODE_TRANSFER;
2122 mode = TOOLBAR_MODE_NORMAL;
2126 /* Add operation observers and change toolbar if neccessary*/
2127 tmp = priv->progress_widgets;
2129 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2130 if (mode == TOOLBAR_MODE_TRANSFER) {
2131 /* Enable transfer toolbar mode */
2132 set_toolbar_transfer_mode(self);
2134 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2136 tmp = g_slist_next (tmp);
2141 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2142 if (mode == TOOLBAR_MODE_TRANSFER) {
2144 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2146 tmp = g_slist_next (tmp);
2150 /* If no more operations are being observed, NORMAL mode is enabled again */
2151 if (observers_empty (self)) {
2152 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2160 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2162 ModestMsgViewWindowPrivate *priv;
2163 GList *selected_attachments = NULL;
2165 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2166 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2168 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2170 return selected_attachments;
2174 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2176 ModestMsgViewWindowPrivate *priv;
2177 const gchar *msg_uid;
2178 gchar *attachment_uid = NULL;
2179 gint attachment_index = 0;
2182 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2183 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2184 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2186 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2187 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2188 attachment_index = g_list_index (attachments, mime_part);
2189 g_list_free (attachments);
2191 if (msg_uid && attachment_index >= 0) {
2192 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2195 if (mime_part == NULL) {
2196 gboolean error = FALSE;
2197 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2198 if (selected_attachments == NULL) {
2200 } else if (g_list_length (selected_attachments) > 1) {
2201 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2204 mime_part = (TnyMimePart *) selected_attachments->data;
2205 g_object_ref (mime_part);
2207 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2208 g_list_free (selected_attachments);
2213 g_object_ref (mime_part);
2216 if (tny_mime_part_is_purged (mime_part)) {
2217 g_object_unref (mime_part);
2221 if (!TNY_IS_MSG (mime_part)) {
2222 gchar *filepath = NULL;
2223 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2224 TnyFsStream *temp_stream = NULL;
2225 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2228 const gchar *content_type;
2229 content_type = tny_mime_part_get_content_type (mime_part);
2230 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2232 modest_platform_activate_file (filepath, content_type);
2233 g_object_unref (temp_stream);
2235 /* NOTE: files in the temporary area will be automatically
2236 * cleaned after some time if they are no longer in use */
2239 /* message attachment */
2240 TnyHeader *header = NULL;
2241 ModestWindowMgr *mgr;
2242 ModestWindow *msg_win = NULL;
2245 header = tny_msg_get_header (TNY_MSG (mime_part));
2246 mgr = modest_runtime_get_window_mgr ();
2247 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2250 if (msg_win) /* there is already a window for this uid; top it */
2251 gtk_window_present (GTK_WINDOW(msg_win));
2253 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2254 * thus, we don't do anything */
2255 g_warning ("window for is already being created");
2257 /* it's not found, so create a new window for it */
2258 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2259 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2261 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2262 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2263 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2264 modest_window_get_zoom (MODEST_WINDOW (window)));
2265 modest_window_mgr_register_window (mgr, msg_win);
2266 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2267 gtk_widget_show_all (GTK_WIDGET (msg_win));
2270 g_object_unref (mime_part);
2286 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2287 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2288 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2289 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2292 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2296 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2297 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2298 g_free (pair->filename);
2299 g_object_unref (pair->part);
2300 g_slice_free (SaveMimePartPair, pair);
2302 g_list_free (info->pairs);
2305 gtk_widget_destroy (info->banner);
2306 g_object_unref (info->banner);
2307 g_slice_free (SaveMimePartInfo, info);
2312 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2314 if (info->pairs != NULL) {
2315 save_mime_part_to_file (info);
2318 result = info->result;
2320 /* This is a GDK lock because we are an idle callback and
2321 * hildon_banner_show_information is or does Gtk+ code */
2323 gdk_threads_enter (); /* CHECKED */
2324 save_mime_part_info_free (info, TRUE);
2326 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2328 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2330 gdk_threads_leave (); /* CHECKED */
2337 save_mime_part_to_file (SaveMimePartInfo *info)
2339 GnomeVFSResult result;
2340 GnomeVFSHandle *handle;
2342 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2344 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0444);
2345 if (result == GNOME_VFS_OK) {
2346 stream = tny_vfs_stream_new (handle);
2347 tny_mime_part_decode_to_stream (pair->part, stream);
2348 g_object_unref (G_OBJECT (stream));
2349 g_object_unref (pair->part);
2350 g_slice_free (SaveMimePartPair, pair);
2351 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2352 info->result = TRUE;
2354 save_mime_part_info_free (info, FALSE);
2355 info->result = FALSE;
2358 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2363 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2365 gboolean is_ok = TRUE;
2366 gint replaced_files = 0;
2367 const GList *files = info->pairs;
2370 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2371 SaveMimePartPair *pair = iter->data;
2372 if (modest_maemo_utils_file_exists (pair->filename)) {
2376 if (replaced_files) {
2377 GtkWidget *confirm_overwrite_dialog;
2378 const gchar *message = (replaced_files == 1) ?
2379 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2380 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2381 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2384 gtk_widget_destroy (confirm_overwrite_dialog);
2388 save_mime_part_info_free (info, TRUE);
2390 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2391 _CS("sfil_ib_saving"));
2392 info->banner = g_object_ref (banner);
2393 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2394 g_object_unref (banner);
2401 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2403 gboolean clean_list = FALSE;
2404 ModestMsgViewWindowPrivate *priv;
2405 GList *files_to_save = NULL;
2406 GtkWidget *save_dialog = NULL;
2407 gchar *folder = NULL;
2408 gboolean canceled = FALSE;
2409 const gchar *filename = NULL;
2410 gchar *save_multiple_str = NULL;
2412 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2413 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2415 if (mime_parts == NULL) {
2416 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2417 if (mime_parts == NULL)
2422 /* prepare dialog */
2423 if (mime_parts->next == NULL) {
2424 /* only one attachment selected */
2425 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2426 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2427 filename = tny_mime_part_get_filename (mime_part);
2429 g_warning ("Tried to save a non-file attachment");
2433 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2434 g_list_length (mime_parts));
2437 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2438 GTK_FILE_CHOOSER_ACTION_SAVE);
2441 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2442 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2446 if (filename != NULL)
2447 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2450 /* if multiple, set multiple string */
2451 if (save_multiple_str) {
2452 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2456 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2457 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2459 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2460 hildon_banner_show_information
2461 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2465 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2466 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2468 if (tny_mime_part_is_attachment (mime_part)) {
2469 SaveMimePartPair *pair;
2471 if ((mime_parts->next != NULL) &&
2472 (tny_mime_part_get_filename (mime_part) == NULL))
2475 pair = g_slice_new0 (SaveMimePartPair);
2476 if (mime_parts->next == NULL) {
2477 pair->filename = g_strdup (chooser_uri);
2480 g_build_filename (chooser_uri,
2481 tny_mime_part_get_filename (mime_part), NULL);
2483 pair->part = g_object_ref (mime_part);
2484 files_to_save = g_list_prepend (files_to_save, pair);
2488 g_free (chooser_uri);
2491 gtk_widget_destroy (save_dialog);
2494 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2495 g_list_free (mime_parts);
2498 if (files_to_save != NULL) {
2499 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2500 info->pairs = files_to_save;
2501 info->result = TRUE;
2502 save_mime_parts_to_file_with_checks (info);
2507 show_remove_attachment_information (gpointer userdata)
2509 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2510 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2512 if (priv->remove_attachment_banner != NULL) {
2513 gtk_widget_destroy (priv->remove_attachment_banner);
2514 g_object_unref (priv->remove_attachment_banner);
2517 priv->remove_attachment_banner = g_object_ref (
2518 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2524 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2526 ModestMsgViewWindowPrivate *priv;
2527 GList *mime_parts = NULL, *node;
2528 gchar *confirmation_message;
2532 /* TnyFolder *folder; */
2534 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2535 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2538 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2540 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2542 /* Remove already purged messages from mime parts list */
2544 while (node != NULL) {
2545 TnyMimePart *part = TNY_MIME_PART (node->data);
2546 if (tny_mime_part_is_purged (part)) {
2547 GList *deleted_node = node;
2548 node = g_list_next (node);
2549 g_object_unref (part);
2550 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2552 node = g_list_next (node);
2556 if (mime_parts == NULL)
2559 n_attachments = g_list_length (mime_parts);
2560 if (n_attachments == 1) {
2561 const gchar *filename;
2563 if (TNY_IS_MSG (mime_parts->data)) {
2565 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2566 filename = tny_header_get_subject (header);
2567 g_object_unref (header);
2568 if (filename == NULL)
2569 filename = _("mail_va_no_subject");
2571 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2573 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2575 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2576 "mcen_nc_purge_files_text",
2577 n_attachments), n_attachments);
2579 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2580 confirmation_message);
2581 g_free (confirmation_message);
2583 if (response != GTK_RESPONSE_OK)
2586 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2587 /* folder = tny_msg_get_folder (msg); */
2588 /* tny_msg_uncache_attachments (msg); */
2589 /* tny_folder_refresh (folder, NULL); */
2590 /* g_object_unref (folder); */
2592 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2593 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2594 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2597 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2598 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2599 tny_msg_rewrite_cache (msg);
2600 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2602 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2603 g_list_free (mime_parts);
2605 if (priv->purge_timeout > 0) {
2606 g_source_remove (priv->purge_timeout);
2607 priv->purge_timeout = 0;
2610 if (priv->remove_attachment_banner) {
2611 gtk_widget_destroy (priv->remove_attachment_banner);
2612 g_object_unref (priv->remove_attachment_banner);
2613 priv->remove_attachment_banner = NULL;
2621 update_window_title (ModestMsgViewWindow *window)
2623 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2625 TnyHeader *header = NULL;
2626 const gchar *subject = NULL;
2628 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2631 header = tny_msg_get_header (msg);
2632 subject = tny_header_get_subject (header);
2633 g_object_unref (msg);
2636 if ((subject == NULL)||(subject[0] == '\0'))
2637 subject = _("mail_va_no_subject");
2639 gtk_window_set_title (GTK_WINDOW (window), subject);
2643 static void on_move_focus (ModestMsgViewWindow *window,
2644 GtkDirectionType direction,
2647 GtkWidget *current_focus = NULL;
2649 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2650 if ((current_focus != NULL) &&
2651 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2652 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");