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);
1843 folder_type = tny_folder_get_folder_type (folder);
1845 if (folder_type == TNY_FOLDER_TYPE_NORMAL || folder_type == TNY_FOLDER_TYPE_UNKNOWN) {
1846 const gchar *fname = tny_folder_get_name (folder);
1847 folder_type = modest_tny_folder_guess_folder_type_from_name (fname);
1850 g_object_unref (folder);
1852 g_object_unref (msg);
1860 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1862 ModestMsgViewWindowPrivate *priv;
1863 TnyHeaderFlags flags = 0;
1865 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1867 if (priv->header_model) {
1870 GtkTreePath *path = NULL;
1872 path = gtk_tree_row_reference_get_path (priv->row_reference);
1873 g_return_if_fail (path != NULL);
1874 gtk_tree_model_get_iter (priv->header_model,
1876 gtk_tree_row_reference_get_path (priv->row_reference));
1878 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1880 flags = tny_header_get_flags (header);
1881 gtk_tree_path_free (path);
1884 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1889 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1891 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1892 ModestWindowPrivate *parent_priv;
1893 ModestWindowMgr *mgr;
1894 gboolean is_fullscreen;
1895 GtkAction *fs_toggle_action;
1898 mgr = modest_runtime_get_window_mgr ();
1899 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1901 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1903 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1904 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1905 if (is_fullscreen != active) {
1906 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1915 set_homogeneous (GtkWidget *widget,
1918 if (GTK_IS_TOOL_ITEM (widget)) {
1919 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1920 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1925 modest_msg_view_window_show_toolbar (ModestWindow *self,
1926 gboolean show_toolbar)
1928 ModestMsgViewWindowPrivate *priv = NULL;
1929 ModestWindowPrivate *parent_priv;
1930 GtkWidget *reply_button = NULL, *menu = NULL;
1931 GtkWidget *placeholder = NULL;
1933 const gchar *action_name;
1936 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1937 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1939 /* Set optimized view status */
1940 priv->optimized_view = !show_toolbar;
1942 if (!parent_priv->toolbar) {
1943 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1945 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1947 /* Set homogeneous toolbar */
1948 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1949 set_homogeneous, NULL);
1951 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1952 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1953 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1954 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1955 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1956 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1957 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1958 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1960 /* Add ProgressBar (Transfer toolbar) */
1961 priv->progress_bar = modest_progress_bar_widget_new ();
1962 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1963 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1964 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1965 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1966 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1968 /* Connect cancel 'clicked' signal to abort progress mode */
1969 g_signal_connect(priv->cancel_toolitem, "clicked",
1970 G_CALLBACK(cancel_progressbar),
1973 /* Add it to the observers list */
1974 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1977 hildon_window_add_toolbar (HILDON_WINDOW (self),
1978 GTK_TOOLBAR (parent_priv->toolbar));
1981 /* Set reply button tap and hold menu */
1982 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1983 "/ToolBar/ToolbarMessageReply");
1984 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1985 "/ToolbarReplyCSM");
1986 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1990 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1991 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1992 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1994 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1995 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
1998 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1999 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2002 /* Update also the actions (to update the toggles in the
2003 menus), we have to do it manually because some other window
2004 of the same time could have changed it (remember that the
2005 toolbar fullscreen mode is shared by all the windows of the
2007 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2008 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2010 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2012 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2013 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2018 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2020 ModestMsgViewWindow *window)
2022 if (!GTK_WIDGET_VISIBLE (window))
2025 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2029 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2031 ModestMsgViewWindowPrivate *priv;
2033 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2034 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2036 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2040 cancel_progressbar (GtkToolButton *toolbutton,
2041 ModestMsgViewWindow *self)
2044 ModestMsgViewWindowPrivate *priv;
2046 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2048 /* Get operation observers and cancel its current operation */
2049 tmp = priv->progress_widgets;
2051 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2052 tmp=g_slist_next(tmp);
2056 observers_empty (ModestMsgViewWindow *self)
2059 ModestMsgViewWindowPrivate *priv;
2060 gboolean is_empty = TRUE;
2061 guint pending_ops = 0;
2063 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2064 tmp = priv->progress_widgets;
2066 /* Check all observers */
2067 while (tmp && is_empty) {
2068 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2069 is_empty = pending_ops == 0;
2071 tmp = g_slist_next(tmp);
2078 on_account_removed (TnyAccountStore *account_store,
2079 TnyAccount *account,
2082 /* Do nothing if it's a transport account, because we only
2083 show the messages of a store account */
2084 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2085 const gchar *parent_acc = NULL;
2086 const gchar *our_acc = NULL;
2088 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2089 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2091 /* Close this window if I'm showing a message of the removed account */
2092 if (strcmp (parent_acc, our_acc) == 0)
2093 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2098 on_queue_changed (ModestMailOperationQueue *queue,
2099 ModestMailOperation *mail_op,
2100 ModestMailOperationQueueNotification type,
2101 ModestMsgViewWindow *self)
2104 ModestMsgViewWindowPrivate *priv;
2105 ModestMailOperationTypeOperation op_type;
2106 ModestToolBarModes mode;
2108 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2109 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2111 /* If this operations was created by another window, do nothing */
2112 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2115 /* Get toolbar mode from operation id*/
2116 op_type = modest_mail_operation_get_type_operation (mail_op);
2118 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2119 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2120 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2121 mode = TOOLBAR_MODE_TRANSFER;
2124 mode = TOOLBAR_MODE_NORMAL;
2128 /* Add operation observers and change toolbar if neccessary*/
2129 tmp = priv->progress_widgets;
2131 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2132 if (mode == TOOLBAR_MODE_TRANSFER) {
2133 /* Enable transfer toolbar mode */
2134 set_toolbar_transfer_mode(self);
2136 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2138 tmp = g_slist_next (tmp);
2143 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2144 if (mode == TOOLBAR_MODE_TRANSFER) {
2146 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2148 tmp = g_slist_next (tmp);
2152 /* If no more operations are being observed, NORMAL mode is enabled again */
2153 if (observers_empty (self)) {
2154 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2162 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2164 ModestMsgViewWindowPrivate *priv;
2165 GList *selected_attachments = NULL;
2167 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2168 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2170 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2172 return selected_attachments;
2176 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2178 ModestMsgViewWindowPrivate *priv;
2179 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2180 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2182 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2184 if (mime_part == NULL) {
2185 gboolean error = FALSE;
2186 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2187 if (selected_attachments == NULL) {
2189 } else if (g_list_length (selected_attachments) > 1) {
2190 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2193 mime_part = (TnyMimePart *) selected_attachments->data;
2194 g_object_ref (mime_part);
2196 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2197 g_list_free (selected_attachments);
2202 g_object_ref (mime_part);
2205 if (tny_mime_part_is_purged (mime_part)) {
2206 g_object_unref (mime_part);
2210 if (!TNY_IS_MSG (mime_part)) {
2211 gchar *filepath = NULL;
2212 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2213 TnyFsStream *temp_stream = NULL;
2215 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, &filepath);
2218 const gchar *content_type;
2219 content_type = tny_mime_part_get_content_type (mime_part);
2220 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2222 modest_platform_activate_file (filepath, content_type);
2223 g_object_unref (temp_stream);
2225 /* NOTE: files in the temporary area will be automatically
2226 * cleaned after some time if they are no longer in use */
2229 /* message attachment */
2230 TnyHeader *header = NULL;
2231 ModestWindowMgr *mgr;
2232 ModestWindow *msg_win = NULL;
2235 header = tny_msg_get_header (TNY_MSG (mime_part));
2236 mgr = modest_runtime_get_window_mgr ();
2237 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2240 if (msg_win) /* there is already a window for this uid; top it */
2241 gtk_window_present (GTK_WINDOW(msg_win));
2243 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2244 * thus, we don't do anything */
2245 g_warning ("window for is already being created");
2247 /* it's not found, so create a new window for it */
2248 modest_window_mgr_register_header (mgr, header); /* register the uid before building the window */
2249 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2251 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2252 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, NULL);
2253 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2254 modest_window_get_zoom (MODEST_WINDOW (window)));
2255 modest_window_mgr_register_window (mgr, msg_win);
2256 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2257 gtk_widget_show_all (GTK_WIDGET (msg_win));
2260 g_object_unref (mime_part);
2276 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2277 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2278 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2279 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2282 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2286 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2287 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2288 g_free (pair->filename);
2289 g_object_unref (pair->part);
2290 g_slice_free (SaveMimePartPair, pair);
2292 g_list_free (info->pairs);
2295 gtk_widget_destroy (info->banner);
2296 g_object_unref (info->banner);
2297 g_slice_free (SaveMimePartInfo, info);
2302 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2304 if (info->pairs != NULL) {
2305 save_mime_part_to_file (info);
2308 result = info->result;
2310 /* This is a GDK lock because we are an idle callback and
2311 * hildon_banner_show_information is or does Gtk+ code */
2313 gdk_threads_enter (); /* CHECKED */
2314 save_mime_part_info_free (info, TRUE);
2316 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2318 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2320 gdk_threads_leave (); /* CHECKED */
2327 save_mime_part_to_file (SaveMimePartInfo *info)
2329 GnomeVFSResult result;
2330 GnomeVFSHandle *handle;
2332 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2334 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0777);
2335 if (result == GNOME_VFS_OK) {
2336 stream = tny_vfs_stream_new (handle);
2337 tny_mime_part_decode_to_stream (pair->part, stream);
2338 g_object_unref (G_OBJECT (stream));
2339 g_object_unref (pair->part);
2340 g_slice_free (SaveMimePartPair, pair);
2341 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2342 info->result = TRUE;
2344 save_mime_part_info_free (info, FALSE);
2345 info->result = FALSE;
2348 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2353 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2355 gboolean is_ok = TRUE;
2356 gint replaced_files = 0;
2357 const GList *files = info->pairs;
2360 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2361 SaveMimePartPair *pair = iter->data;
2362 if (modest_maemo_utils_file_exists (pair->filename)) {
2366 if (replaced_files) {
2367 GtkWidget *confirm_overwrite_dialog;
2368 const gchar *message = (replaced_files == 1) ?
2369 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2370 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2371 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2374 gtk_widget_destroy (confirm_overwrite_dialog);
2378 save_mime_part_info_free (info, TRUE);
2380 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2381 _CS("sfil_ib_saving"));
2382 info->banner = g_object_ref (banner);
2383 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2384 g_object_unref (banner);
2391 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2393 gboolean clean_list = FALSE;
2394 ModestMsgViewWindowPrivate *priv;
2395 GList *files_to_save = NULL;
2396 GtkWidget *save_dialog = NULL;
2397 gchar *folder = NULL;
2398 gboolean canceled = FALSE;
2399 const gchar *filename = NULL;
2400 gchar *save_multiple_str = NULL;
2402 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2403 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2405 if (mime_parts == NULL) {
2406 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2407 if (mime_parts == NULL)
2412 /* prepare dialog */
2413 if (mime_parts->next == NULL) {
2414 /* only one attachment selected */
2415 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2416 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2417 filename = tny_mime_part_get_filename (mime_part);
2419 g_warning ("Tried to save a non-file attachment");
2423 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2424 g_list_length (mime_parts));
2427 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2428 GTK_FILE_CHOOSER_ACTION_SAVE);
2431 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2432 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2436 if (filename != NULL)
2437 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2440 /* if multiple, set multiple string */
2441 if (save_multiple_str) {
2442 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2446 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2447 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2449 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2450 hildon_banner_show_information
2451 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2455 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2456 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2458 if (tny_mime_part_is_attachment (mime_part)) {
2459 SaveMimePartPair *pair;
2461 if ((mime_parts->next != NULL) &&
2462 (tny_mime_part_get_filename (mime_part) == NULL))
2465 pair = g_slice_new0 (SaveMimePartPair);
2466 if (mime_parts->next == NULL) {
2467 pair->filename = g_strdup (chooser_uri);
2470 g_build_filename (chooser_uri,
2471 tny_mime_part_get_filename (mime_part), NULL);
2473 pair->part = g_object_ref (mime_part);
2474 files_to_save = g_list_prepend (files_to_save, pair);
2478 g_free (chooser_uri);
2481 gtk_widget_destroy (save_dialog);
2484 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2485 g_list_free (mime_parts);
2488 if (files_to_save != NULL) {
2489 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2490 info->pairs = files_to_save;
2491 info->result = TRUE;
2492 save_mime_parts_to_file_with_checks (info);
2497 show_remove_attachment_information (gpointer userdata)
2499 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2500 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2502 if (priv->remove_attachment_banner != NULL) {
2503 gtk_widget_destroy (priv->remove_attachment_banner);
2504 g_object_unref (priv->remove_attachment_banner);
2507 priv->remove_attachment_banner = g_object_ref (
2508 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2514 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2516 ModestMsgViewWindowPrivate *priv;
2517 GList *mime_parts = NULL, *node;
2518 gchar *confirmation_message;
2522 /* TnyFolder *folder; */
2524 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2525 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2528 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2530 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2532 /* Remove already purged messages from mime parts list */
2534 while (node != NULL) {
2535 TnyMimePart *part = TNY_MIME_PART (node->data);
2536 if (tny_mime_part_is_purged (part)) {
2537 GList *deleted_node = node;
2538 node = g_list_next (node);
2539 g_object_unref (part);
2540 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2542 node = g_list_next (node);
2546 if (mime_parts == NULL)
2549 n_attachments = g_list_length (mime_parts);
2550 if (n_attachments == 1) {
2551 const gchar *filename;
2553 if (TNY_IS_MSG (mime_parts->data)) {
2555 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2556 filename = tny_header_get_subject (header);
2557 g_object_unref (header);
2558 if (filename == NULL)
2559 filename = _("mail_va_no_subject");
2561 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2563 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2565 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2566 "mcen_nc_purge_files_text",
2567 n_attachments), n_attachments);
2569 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2570 confirmation_message);
2571 g_free (confirmation_message);
2573 if (response != GTK_RESPONSE_OK)
2576 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2577 /* folder = tny_msg_get_folder (msg); */
2578 /* tny_msg_uncache_attachments (msg); */
2579 /* tny_folder_refresh (folder, NULL); */
2580 /* g_object_unref (folder); */
2582 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2583 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2584 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2587 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2588 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2589 tny_msg_rewrite_cache (msg);
2590 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2592 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2593 g_list_free (mime_parts);
2595 if (priv->purge_timeout > 0) {
2596 g_source_remove (priv->purge_timeout);
2597 priv->purge_timeout = 0;
2600 if (priv->remove_attachment_banner) {
2601 gtk_widget_destroy (priv->remove_attachment_banner);
2602 g_object_unref (priv->remove_attachment_banner);
2603 priv->remove_attachment_banner = NULL;
2611 update_window_title (ModestMsgViewWindow *window)
2613 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2615 TnyHeader *header = NULL;
2616 const gchar *subject = NULL;
2618 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2620 header = tny_msg_get_header (msg);
2621 subject = tny_header_get_subject (header);
2622 g_object_unref (msg);
2625 if ((subject == NULL)||(subject[0] == '\0'))
2626 subject = _("mail_va_no_subject");
2628 gtk_window_set_title (GTK_WINDOW (window), subject);
2631 static void on_move_focus (ModestMsgViewWindow *window,
2632 GtkDirectionType direction,
2635 GtkWidget *current_focus = NULL;
2637 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2638 if ((current_focus != NULL) &&
2639 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2640 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");