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 #include <glib/gstdio.h>
62 #define DEFAULT_FOLDER "MyDocs/.documents"
64 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
65 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
66 static void modest_header_view_observer_init(
67 ModestHeaderViewObserverIface *iface_class);
68 static void modest_msg_view_window_finalize (GObject *obj);
69 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
71 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
72 ModestMsgViewWindow *obj);
73 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
74 ModestMsgViewWindow *obj);
76 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
77 static void modest_msg_view_window_set_zoom (ModestWindow *window,
79 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
80 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
81 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
82 static gboolean modest_msg_view_window_key_release_event (GtkWidget *window,
85 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
86 GdkEventWindowState *event,
88 static void modest_msg_view_window_scroll_up (ModestWindow *window);
89 static void modest_msg_view_window_scroll_down (ModestWindow *window);
90 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
92 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
93 gboolean show_toolbar);
95 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
97 ModestMsgViewWindow *window);
98 void modest_msg_view_window_on_row_changed(
99 GtkTreeModel *header_model,
102 ModestMsgViewWindow *window);
104 void modest_msg_view_window_on_row_deleted(
105 GtkTreeModel *header_model,
107 ModestMsgViewWindow *window);
109 void modest_msg_view_window_on_row_inserted(
110 GtkTreeModel *header_model,
111 GtkTreePath *tree_path,
112 GtkTreeIter *tree_iter,
113 ModestMsgViewWindow *window);
115 void modest_msg_view_window_on_row_reordered(
116 GtkTreeModel *header_model,
120 ModestMsgViewWindow *window);
122 void modest_msg_view_window_update_model_replaced(
123 ModestHeaderViewObserver *window,
125 const gchar *tny_folder_id);
127 static void cancel_progressbar (GtkToolButton *toolbutton,
128 ModestMsgViewWindow *self);
130 static void on_queue_changed (ModestMailOperationQueue *queue,
131 ModestMailOperation *mail_op,
132 ModestMailOperationQueueNotification type,
133 ModestMsgViewWindow *self);
135 static void on_account_removed (TnyAccountStore *account_store,
139 static void on_move_focus (ModestMsgViewWindow *window,
140 GtkDirectionType direction,
143 static void view_msg_cb (ModestMailOperation *mail_op,
150 static void set_toolbar_mode (ModestMsgViewWindow *self,
151 ModestToolBarModes mode);
153 static void update_window_title (ModestMsgViewWindow *window);
155 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
156 static void init_window (ModestMsgViewWindow *obj);
159 /* list my signals */
165 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
166 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
167 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
170 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
171 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
172 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
173 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
174 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
175 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
176 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
179 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
180 struct _ModestMsgViewWindowPrivate {
183 GtkWidget *main_scroll;
184 GtkWidget *find_toolbar;
187 /* Progress observers */
188 GtkWidget *progress_bar;
189 GSList *progress_widgets;
192 GtkWidget *progress_toolitem;
193 GtkWidget *cancel_toolitem;
194 GtkWidget *prev_toolitem;
195 GtkWidget *next_toolitem;
196 ModestToolBarModes current_toolbar_mode;
198 /* Optimized view enabled */
199 gboolean optimized_view;
201 /* Whether this was created via the *_new_for_search_result() function. */
202 gboolean is_search_result;
204 /* A reference to the @model of the header view
205 * to allow selecting previous/next messages,
206 * if the message is currently selected in the header view.
208 const gchar *header_folder_id;
209 GtkTreeModel *header_model;
210 GtkTreeRowReference *row_reference;
211 GtkTreeRowReference *next_row_reference;
213 gulong clipboard_change_handler;
214 gulong queue_change_handler;
215 gulong account_removed_handler;
216 gulong row_changed_handler;
217 gulong row_deleted_handler;
218 gulong row_inserted_handler;
219 gulong rows_reordered_handler;
222 GtkWidget *remove_attachment_banner;
224 guint progress_bar_timeout;
229 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
230 MODEST_TYPE_MSG_VIEW_WINDOW, \
231 ModestMsgViewWindowPrivate))
233 static GtkWindowClass *parent_class = NULL;
235 /* uncomment the following if you have defined any signals */
236 static guint signals[LAST_SIGNAL] = {0};
239 modest_msg_view_window_get_type (void)
241 static GType my_type = 0;
243 static const GTypeInfo my_info = {
244 sizeof(ModestMsgViewWindowClass),
245 NULL, /* base init */
246 NULL, /* base finalize */
247 (GClassInitFunc) modest_msg_view_window_class_init,
248 NULL, /* class finalize */
249 NULL, /* class data */
250 sizeof(ModestMsgViewWindow),
252 (GInstanceInitFunc) modest_msg_view_window_init,
255 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
256 "ModestMsgViewWindow",
259 static const GInterfaceInfo modest_header_view_observer_info =
261 (GInterfaceInitFunc) modest_header_view_observer_init,
262 NULL, /* interface_finalize */
263 NULL /* interface_data */
266 g_type_add_interface_static (my_type,
267 MODEST_TYPE_HEADER_VIEW_OBSERVER,
268 &modest_header_view_observer_info);
274 save_state (ModestWindow *self)
276 modest_widget_memory_save (modest_runtime_get_conf (),
278 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
283 restore_settings (ModestMsgViewWindow *self)
285 modest_widget_memory_restore (modest_runtime_get_conf (),
287 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
291 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
293 GObjectClass *gobject_class;
294 ModestWindowClass *modest_window_class;
295 gobject_class = (GObjectClass*) klass;
296 modest_window_class = (ModestWindowClass *) klass;
298 parent_class = g_type_class_peek_parent (klass);
299 gobject_class->finalize = modest_msg_view_window_finalize;
301 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
302 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
303 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
304 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
305 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
306 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
308 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
310 modest_window_class->save_state_func = save_state;
312 signals[MSG_CHANGED_SIGNAL] =
313 g_signal_new ("msg-changed",
314 G_TYPE_FROM_CLASS (gobject_class),
316 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
318 modest_marshal_VOID__POINTER_POINTER,
319 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
322 static void modest_header_view_observer_init(
323 ModestHeaderViewObserverIface *iface_class)
325 iface_class->update_func = modest_msg_view_window_update_model_replaced;
329 modest_msg_view_window_init (ModestMsgViewWindow *obj)
331 ModestMsgViewWindowPrivate *priv;
332 ModestWindowPrivate *parent_priv = NULL;
333 GtkActionGroup *action_group = NULL;
334 GError *error = NULL;
335 GdkPixbuf *window_icon;
337 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
338 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
339 parent_priv->ui_manager = gtk_ui_manager_new();
341 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
342 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
344 /* Add common actions */
345 gtk_action_group_add_actions (action_group,
346 modest_action_entries,
347 G_N_ELEMENTS (modest_action_entries),
349 gtk_action_group_add_toggle_actions (action_group,
350 modest_toggle_action_entries,
351 G_N_ELEMENTS (modest_toggle_action_entries),
353 gtk_action_group_add_toggle_actions (action_group,
354 msg_view_toggle_action_entries,
355 G_N_ELEMENTS (msg_view_toggle_action_entries),
357 gtk_action_group_add_radio_actions (action_group,
358 msg_view_zoom_action_entries,
359 G_N_ELEMENTS (msg_view_zoom_action_entries),
361 G_CALLBACK (modest_ui_actions_on_change_zoom),
364 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
365 g_object_unref (action_group);
367 /* Load the UI definition */
368 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
371 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
372 g_error_free (error);
377 /* Add accelerators */
378 gtk_window_add_accel_group (GTK_WINDOW (obj),
379 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
381 priv->is_search_result = FALSE;
383 priv->msg_view = NULL;
384 priv->header_model = NULL;
385 priv->header_folder_id = NULL;
386 priv->clipboard_change_handler = 0;
387 priv->queue_change_handler = 0;
388 priv->account_removed_handler = 0;
389 priv->row_changed_handler = 0;
390 priv->row_deleted_handler = 0;
391 priv->row_inserted_handler = 0;
392 priv->rows_reordered_handler = 0;
393 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
395 priv->optimized_view = FALSE;
396 priv->progress_bar_timeout = 0;
397 priv->purge_timeout = 0;
398 priv->remove_attachment_banner = NULL;
399 priv->msg_uid = NULL;
402 init_window (MODEST_MSG_VIEW_WINDOW(obj));
403 /* Set window icon */
404 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
406 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
407 g_object_unref (window_icon);
411 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
412 GTK_WINDOW(obj),"applications_email_viewer");
417 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
419 ModestMsgViewWindowPrivate *priv = NULL;
421 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
423 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
425 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
427 if (priv->progress_bar_timeout > 0) {
428 g_source_remove (priv->progress_bar_timeout);
429 priv->progress_bar_timeout = 0;
436 set_toolbar_mode (ModestMsgViewWindow *self,
437 ModestToolBarModes mode)
439 ModestWindowPrivate *parent_priv;
440 ModestMsgViewWindowPrivate *priv;
441 /* GtkWidget *widget = NULL; */
443 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
445 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
446 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
448 /* Sets current toolbar mode */
449 priv->current_toolbar_mode = mode;
451 /* Update toolbar dimming state */
452 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
455 case TOOLBAR_MODE_NORMAL:
456 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
457 /* gtk_action_set_sensitive (widget, TRUE); */
458 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
459 /* gtk_action_set_sensitive (widget, TRUE); */
460 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
461 /* gtk_action_set_sensitive (widget, TRUE); */
462 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
463 /* gtk_action_set_sensitive (widget, TRUE); */
465 if (priv->prev_toolitem)
466 gtk_widget_show (priv->prev_toolitem);
468 if (priv->next_toolitem)
469 gtk_widget_show (priv->next_toolitem);
471 if (priv->progress_toolitem)
472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
473 if (priv->progress_bar)
474 gtk_widget_hide (priv->progress_bar);
476 if (priv->cancel_toolitem)
477 gtk_widget_hide (priv->cancel_toolitem);
479 /* Hide toolbar if optimized view is enabled */
480 if (priv->optimized_view) {
481 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
482 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
486 case TOOLBAR_MODE_TRANSFER:
487 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
488 /* gtk_action_set_sensitive (widget, FALSE); */
489 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
490 /* gtk_action_set_sensitive (widget, FALSE); */
491 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
492 /* gtk_action_set_sensitive (widget, FALSE); */
493 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
494 /* gtk_action_set_sensitive (widget, FALSE); */
496 if (priv->prev_toolitem)
497 gtk_widget_hide (priv->prev_toolitem);
499 if (priv->next_toolitem)
500 gtk_widget_hide (priv->next_toolitem);
502 if (priv->progress_toolitem)
503 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
504 if (priv->progress_bar)
505 gtk_widget_show (priv->progress_bar);
507 if (priv->cancel_toolitem)
508 gtk_widget_show (priv->cancel_toolitem);
510 /* Show toolbar if it's hiden (optimized view ) */
511 if (priv->optimized_view) {
512 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
513 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
518 g_return_if_reached ();
525 menubar_to_menu (GtkUIManager *ui_manager)
527 GtkWidget *main_menu;
529 GList *iter, *children;
531 /* Create new main menu */
532 main_menu = gtk_menu_new();
534 /* Get the menubar from the UI manager */
535 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
537 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
541 menu = GTK_WIDGET (iter->data);
542 gtk_widget_reparent(menu, main_menu);
544 iter = g_list_next (iter);
546 g_list_free (children);
552 init_window (ModestMsgViewWindow *obj)
554 GtkWidget *main_vbox;
555 ModestMsgViewWindowPrivate *priv;
556 ModestWindowPrivate *parent_priv;
558 GtkAction *action = NULL;
560 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
561 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
563 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
564 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
565 main_vbox = gtk_vbox_new (FALSE, 6);
568 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
569 conf = modest_runtime_get_conf ();
570 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
571 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
572 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
573 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
574 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
575 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
576 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
577 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
578 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
579 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
581 #ifdef MODEST_USE_MOZEMBED
582 priv->main_scroll = priv->msg_view;
583 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
585 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
586 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
588 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
589 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
590 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
592 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
593 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
595 priv->find_toolbar = hildon_find_toolbar_new (NULL);
596 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
597 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
598 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
599 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
601 gtk_widget_show_all (GTK_WIDGET(main_vbox));
605 modest_msg_view_window_disconnect_signals (ModestWindow *self)
607 ModestMsgViewWindowPrivate *priv;
608 ModestHeaderView *header_view = NULL;
609 ModestWindow *main_window = NULL;
611 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
613 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
614 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
615 priv->clipboard_change_handler))
616 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
617 priv->clipboard_change_handler);
619 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
620 priv->queue_change_handler))
621 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
622 priv->queue_change_handler);
624 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
625 priv->account_removed_handler))
626 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
627 priv->account_removed_handler);
629 if (priv->header_model) {
630 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
631 priv->row_changed_handler))
632 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
633 priv->row_changed_handler);
635 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
636 priv->row_deleted_handler))
637 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
638 priv->row_deleted_handler);
640 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
641 priv->row_inserted_handler))
642 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
643 priv->row_inserted_handler);
645 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
646 priv->rows_reordered_handler))
647 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
648 priv->rows_reordered_handler);
651 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
652 FALSE); /* don't create */
656 header_view = MODEST_HEADER_VIEW(
657 modest_main_window_get_child_widget(
658 MODEST_MAIN_WINDOW(main_window),
659 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
660 if (header_view == NULL)
663 modest_header_view_remove_observer(header_view,
664 MODEST_HEADER_VIEW_OBSERVER(self));
668 modest_msg_view_window_finalize (GObject *obj)
670 ModestMsgViewWindowPrivate *priv;
672 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
674 /* Sanity check: shouldn't be needed, the window mgr should
675 call this function before */
676 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
678 if (priv->header_model != NULL) {
679 g_object_unref (priv->header_model);
680 priv->header_model = NULL;
683 if (priv->progress_bar_timeout > 0) {
684 g_source_remove (priv->progress_bar_timeout);
685 priv->progress_bar_timeout = 0;
688 if (priv->remove_attachment_banner) {
689 gtk_widget_destroy (priv->remove_attachment_banner);
690 g_object_unref (priv->remove_attachment_banner);
691 priv->remove_attachment_banner = NULL;
694 if (priv->purge_timeout > 0) {
695 g_source_remove (priv->purge_timeout);
696 priv->purge_timeout = 0;
699 if (priv->row_reference) {
700 gtk_tree_row_reference_free (priv->row_reference);
701 priv->row_reference = NULL;
704 if (priv->next_row_reference) {
705 gtk_tree_row_reference_free (priv->next_row_reference);
706 priv->next_row_reference = NULL;
710 g_free (priv->msg_uid);
711 priv->msg_uid = NULL;
714 G_OBJECT_CLASS(parent_class)->finalize (obj);
718 select_next_valid_row (GtkTreeModel *model,
719 GtkTreeRowReference **row_reference,
722 GtkTreeIter tmp_iter;
723 GtkTreePath *path, *next;
724 gboolean retval = FALSE;
726 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
728 path = gtk_tree_row_reference_get_path (*row_reference);
729 gtk_tree_model_get_iter (model, &tmp_iter, path);
730 gtk_tree_row_reference_free (*row_reference);
731 *row_reference = NULL;
733 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
734 next = gtk_tree_model_get_path (model, &tmp_iter);
735 *row_reference = gtk_tree_row_reference_new (model, next);
737 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
738 next = gtk_tree_model_get_path (model, &tmp_iter);
740 /* Ensure that we are not selecting the same */
741 if (gtk_tree_path_compare (path, next) != 0) {
742 *row_reference = gtk_tree_row_reference_new (model, next);
748 gtk_tree_path_free (path);
753 /* TODO: This should be in _init(), with the parameters as properties. */
755 modest_msg_view_window_construct (ModestMsgViewWindow *self,
756 const gchar *modest_account_name,
757 const gchar *msg_uid)
760 ModestMsgViewWindowPrivate *priv = NULL;
761 ModestWindowPrivate *parent_priv = NULL;
762 ModestDimmingRulesGroup *menu_rules_group = NULL;
763 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
764 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
766 obj = G_OBJECT (self);
767 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
768 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
770 priv->msg_uid = g_strdup (msg_uid);
772 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
774 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
775 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
776 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
778 /* Add common dimming rules */
779 modest_dimming_rules_group_add_rules (menu_rules_group,
780 modest_msg_view_menu_dimming_entries,
781 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
782 MODEST_WINDOW (self));
783 modest_dimming_rules_group_add_rules (toolbar_rules_group,
784 modest_msg_view_toolbar_dimming_entries,
785 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
786 MODEST_WINDOW (self));
787 modest_dimming_rules_group_add_rules (clipboard_rules_group,
788 modest_msg_view_clipboard_dimming_entries,
789 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
790 MODEST_WINDOW (self));
792 /* Insert dimming rules group for this window */
793 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
794 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
795 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
796 g_object_unref (menu_rules_group);
797 g_object_unref (toolbar_rules_group);
798 g_object_unref (clipboard_rules_group);
800 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
802 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
804 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);
805 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
806 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
807 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
808 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
809 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
810 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
811 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
812 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
813 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
814 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
816 g_signal_connect (G_OBJECT (obj), "key-release-event",
817 G_CALLBACK (modest_msg_view_window_key_release_event),
820 g_signal_connect (G_OBJECT (obj), "window-state-event",
821 G_CALLBACK (modest_msg_view_window_window_state_event),
824 g_signal_connect (G_OBJECT (obj), "move-focus",
825 G_CALLBACK (on_move_focus), obj);
827 /* Mail Operation Queue */
828 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
830 G_CALLBACK (on_queue_changed),
833 /* Account manager */
834 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
836 G_CALLBACK(on_account_removed),
839 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
841 priv->last_search = NULL;
843 /* Init the clipboard actions dim status */
844 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
846 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
848 /* Check toolbar dimming rules */
849 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
850 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
854 /* FIXME: parameter checks */
856 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
857 const gchar *modest_account_name,
858 const gchar *msg_uid,
860 GtkTreeRowReference *row_reference)
862 ModestMsgViewWindow *window = NULL;
863 ModestMsgViewWindowPrivate *priv = NULL;
864 TnyFolder *header_folder = NULL;
865 ModestHeaderView *header_view = NULL;
866 ModestWindow *main_window = NULL;
867 ModestWindowMgr *mgr = NULL;
869 mgr = modest_runtime_get_window_mgr ();
870 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
871 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
873 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
875 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
877 /* Remember the message list's TreeModel so we can detect changes
878 * and change the list selection when necessary: */
880 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
882 g_warning ("%s: BUG: no main window", __FUNCTION__);
886 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
887 MODEST_MAIN_WINDOW(main_window),
888 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
889 if (header_view != NULL){
890 header_folder = modest_header_view_get_folder(header_view);
891 g_assert(header_folder != NULL);
892 priv->header_folder_id = tny_folder_get_id(header_folder);
893 g_assert(priv->header_folder_id != NULL);
894 g_object_unref(header_folder);
897 priv->header_model = g_object_ref(model);
898 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
899 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
900 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
902 priv->row_changed_handler = g_signal_connect(
903 GTK_TREE_MODEL(model), "row-changed",
904 G_CALLBACK(modest_msg_view_window_on_row_changed),
906 priv->row_deleted_handler = g_signal_connect(
907 GTK_TREE_MODEL(model), "row-deleted",
908 G_CALLBACK(modest_msg_view_window_on_row_deleted),
910 priv->row_inserted_handler = g_signal_connect (
911 GTK_TREE_MODEL(model), "row-inserted",
912 G_CALLBACK(modest_msg_view_window_on_row_inserted),
914 priv->rows_reordered_handler = g_signal_connect(
915 GTK_TREE_MODEL(model), "rows-reordered",
916 G_CALLBACK(modest_msg_view_window_on_row_reordered),
919 if (header_view != NULL){
920 modest_header_view_add_observer(header_view,
921 MODEST_HEADER_VIEW_OBSERVER(window));
924 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
925 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
926 gtk_widget_show_all (GTK_WIDGET (window));
928 modest_msg_view_window_update_priority (window);
930 /* Check toolbar dimming rules */
931 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
933 return MODEST_WINDOW(window);
937 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
938 const gchar *modest_account_name,
939 const gchar *msg_uid)
941 ModestMsgViewWindow *window = NULL;
942 ModestMsgViewWindowPrivate *priv = NULL;
943 ModestWindowMgr *mgr = NULL;
945 mgr = modest_runtime_get_window_mgr ();
946 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
947 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
948 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
950 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
952 /* Remember that this is a search result,
953 * so we can disable some UI appropriately: */
954 priv->is_search_result = TRUE;
956 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
957 update_window_title (window);
959 return MODEST_WINDOW(window);
963 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
964 const gchar *modest_account_name,
965 const gchar *msg_uid)
968 ModestMsgViewWindowPrivate *priv;
969 ModestWindowMgr *mgr = NULL;
971 g_return_val_if_fail (msg, NULL);
972 mgr = modest_runtime_get_window_mgr ();
973 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
974 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
975 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
976 modest_account_name, msg_uid);
978 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
979 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
981 return MODEST_WINDOW(obj);
984 void modest_msg_view_window_on_row_changed(
985 GtkTreeModel *header_model,
988 ModestMsgViewWindow *window){
989 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
992 void modest_msg_view_window_on_row_deleted(
993 GtkTreeModel *header_model,
995 ModestMsgViewWindow *window){
996 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
999 /* On insertions we check if the folder still has the message we are
1000 * showing or do not. If do not, we do nothing. Which means we are still
1001 * not attached to any header folder and thus next/prev buttons are
1002 * still dimmed. Once the message that is shown by msg-view is found, the
1003 * new model of header-view will be attached and the references will be set.
1004 * On each further insertions dimming rules will be checked. However
1005 * this requires extra CPU time at least works.
1006 * (An message might be deleted from TnyFolder and thus will not be
1007 * inserted into the model again for example if it is removed by the
1008 * imap server and the header view is refreshed.)
1010 void modest_msg_view_window_on_row_inserted(
1011 GtkTreeModel *new_model,
1012 GtkTreePath *tree_path,
1013 GtkTreeIter *tree_iter,
1014 ModestMsgViewWindow *window){
1015 ModestMsgViewWindowPrivate *priv = NULL;
1016 TnyHeader *header = NULL;
1019 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1021 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1023 /* If we already has a model attached then the message shown by
1024 * msg-view is in it, and thus we do not need any actions but
1025 * to check the dimming rules.*/
1026 if(priv->header_model != NULL){
1027 gtk_tree_row_reference_free(priv->next_row_reference);
1028 priv->next_row_reference = gtk_tree_row_reference_copy(
1029 priv->row_reference);
1030 select_next_valid_row (priv->header_model,
1031 &(priv->next_row_reference), FALSE);
1032 modest_ui_actions_check_toolbar_dimming_rules (
1033 MODEST_WINDOW (window));
1037 /* Check if the newly inserted message is the same we are actually
1038 * showing. IF not, we should remain detached from the header model
1039 * and thus prev and next toolbarbuttons should remain dimmed. */
1040 gtk_tree_model_get (new_model, tree_iter,
1041 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1042 uid = modest_tny_folder_get_header_unique_id(header);
1043 if(!g_str_equal(priv->msg_uid, uid)){
1049 /* Setup row_reference for the actual msg. */
1050 priv->row_reference = gtk_tree_row_reference_new(
1051 new_model, tree_path);
1052 if(priv->row_reference == NULL){
1053 g_warning("No reference for msg header item.");
1057 /* Attach new_model and connect some callback to it to become able
1058 * to detect changes in header-view. */
1059 priv->header_model = g_object_ref(new_model);
1060 g_signal_connect (new_model, "row-changed",
1061 G_CALLBACK (modest_msg_view_window_on_row_changed),
1063 g_signal_connect (new_model, "row-deleted",
1064 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1066 g_signal_connect (new_model, "rows-reordered",
1067 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1070 /* Now set up next_row_reference. */
1071 priv->next_row_reference = gtk_tree_row_reference_copy(
1072 priv->row_reference);
1073 select_next_valid_row (priv->header_model,
1074 &(priv->next_row_reference), FALSE);
1076 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1079 void modest_msg_view_window_on_row_reordered(
1080 GtkTreeModel *header_model,
1084 ModestMsgViewWindow *window){
1085 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1088 /* The modest_msg_view_window_update_model_replaced implements update
1089 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1090 * actually belongs to the header-view is the same as the TnyFolder of
1091 * the message of msg-view or not. If they are different, there is
1092 * nothing to do. If they are the same, then the model has replaced and
1093 * the reference in msg-view shall be replaced from the old model to
1094 * the new model. In this case the view will be detached from it's
1095 * header folder. From this point the next/prev buttons are dimmed.
1097 void modest_msg_view_window_update_model_replaced(
1098 ModestHeaderViewObserver *observer,
1099 GtkTreeModel *model,
1100 const gchar *tny_folder_id){
1101 ModestMsgViewWindowPrivate *priv = NULL;
1102 ModestMsgViewWindow *window = NULL;
1104 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1105 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1107 window = MODEST_MSG_VIEW_WINDOW(observer);
1108 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1110 /* If there is an other folder in the header-view then we do
1111 * not care about it's model (msg list). Else if the
1112 * header-view shows the folder the msg shown by us is in, we
1113 * shall replace our model reference and make some check. */
1114 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1117 /* Model is changed(replaced), so we should forget the old
1118 * one. Because there might be other references and there
1119 * might be some change on the model even if we unreferenced
1120 * it, we need to disconnect our signals here. */
1121 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1122 priv->row_changed_handler))
1123 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1124 priv->row_changed_handler);
1125 priv->row_changed_handler = 0;
1126 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1127 priv->row_deleted_handler))
1128 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1129 priv->row_deleted_handler);
1130 priv->row_deleted_handler = 0;
1131 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1132 priv->row_inserted_handler))
1133 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1134 priv->row_inserted_handler);
1135 priv->row_inserted_handler = 0;
1136 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1137 priv->rows_reordered_handler))
1138 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1139 priv->rows_reordered_handler);
1140 priv->rows_reordered_handler = 0;
1141 g_object_unref(priv->header_model);
1142 priv->header_model = NULL;
1143 g_object_unref(priv->row_reference);
1144 priv->row_reference = NULL;
1145 g_object_unref(priv->next_row_reference);
1146 priv->next_row_reference = NULL;
1148 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1150 g_assert(model != NULL);
1152 /* Also we must connect to the new model for row insertions.
1153 * Only for insertions now. We will need other ones only after
1154 * the msg is show by msg-view is added to the new model. */
1155 priv->row_inserted_handler = g_signal_connect (
1156 model, "row-inserted",
1157 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1162 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1164 ModestMsgViewWindowPrivate *priv= NULL;
1166 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1167 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1169 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1173 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1175 ModestMsgViewWindowPrivate *priv= NULL;
1177 TnyHeader *header = NULL;
1178 GtkTreePath *path = NULL;
1181 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1182 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1184 /* If the message was not obtained from a treemodel,
1185 * for instance if it was opened directly by the search UI:
1187 if (priv->header_model == NULL) {
1188 msg = modest_msg_view_window_get_message (self);
1190 header = tny_msg_get_header (msg);
1191 g_object_unref (msg);
1196 /* Get iter of the currently selected message in the header view: */
1197 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1198 * instead of sometimes retrieving it from the header view?
1199 * Then we wouldn't be dependent on the message actually still being selected
1200 * in the header view. murrayc. */
1201 if (!gtk_tree_row_reference_valid (priv->row_reference))
1203 path = gtk_tree_row_reference_get_path (priv->row_reference);
1204 g_return_val_if_fail (path != NULL, NULL);
1205 gtk_tree_model_get_iter (priv->header_model,
1209 /* Get current message header */
1210 gtk_tree_model_get (priv->header_model, &iter,
1211 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1214 gtk_tree_path_free (path);
1219 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1221 ModestMsgViewWindowPrivate *priv;
1223 g_return_val_if_fail (self, NULL);
1225 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1227 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1231 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1233 ModestMsgViewWindowPrivate *priv;
1235 g_return_val_if_fail (self, NULL);
1237 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1239 return (const gchar*) priv->msg_uid;
1243 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1246 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1247 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1248 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1252 is_active = gtk_toggle_action_get_active (toggle);
1255 gtk_widget_show (priv->find_toolbar);
1256 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1258 gtk_widget_hide (priv->find_toolbar);
1261 /* update the toggle buttons status */
1262 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1263 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1264 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1265 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1270 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1271 ModestMsgViewWindow *obj)
1273 GtkToggleAction *toggle;
1274 ModestWindowPrivate *parent_priv;
1275 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1277 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1278 gtk_toggle_action_set_active (toggle, FALSE);
1282 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1283 ModestMsgViewWindow *obj)
1285 gchar *current_search;
1286 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1288 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1289 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1293 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1295 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1296 g_free (current_search);
1297 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1301 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1303 g_free (priv->last_search);
1304 priv->last_search = g_strdup (current_search);
1305 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1308 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1309 g_free (priv->last_search);
1310 priv->last_search = NULL;
1312 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1315 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1316 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1317 g_free (priv->last_search);
1318 priv->last_search = NULL;
1320 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1324 g_free (current_search);
1329 modest_msg_view_window_set_zoom (ModestWindow *window,
1332 ModestMsgViewWindowPrivate *priv;
1333 ModestWindowPrivate *parent_priv;
1334 GtkAction *action = NULL;
1335 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1337 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1339 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1340 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1341 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1343 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1344 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1346 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1350 modest_msg_view_window_get_zoom (ModestWindow *window)
1352 ModestMsgViewWindowPrivate *priv;
1354 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1356 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1357 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1361 modest_msg_view_window_zoom_plus (ModestWindow *window)
1363 ModestWindowPrivate *parent_priv;
1364 GtkRadioAction *zoom_radio_action;
1365 GSList *group, *node;
1367 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1368 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1369 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1371 group = gtk_radio_action_get_group (zoom_radio_action);
1373 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1374 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1378 for (node = group; node != NULL; node = g_slist_next (node)) {
1379 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1380 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1388 modest_msg_view_window_zoom_minus (ModestWindow *window)
1390 ModestWindowPrivate *parent_priv;
1391 GtkRadioAction *zoom_radio_action;
1392 GSList *group, *node;
1394 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1395 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1396 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1398 group = gtk_radio_action_get_group (zoom_radio_action);
1400 for (node = group; node != NULL; node = g_slist_next (node)) {
1401 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1402 if (node->next != NULL) {
1403 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1406 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1416 modest_msg_view_window_key_release_event (GtkWidget *window,
1420 if (event->type == GDK_KEY_RELEASE) {
1421 switch (event->keyval) {
1423 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1427 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1440 modest_msg_view_window_scroll_up (ModestWindow *window)
1442 ModestMsgViewWindowPrivate *priv;
1443 gboolean return_value;
1445 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1446 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1450 modest_msg_view_window_scroll_down (ModestWindow *window)
1452 ModestMsgViewWindowPrivate *priv;
1453 gboolean return_value;
1455 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1456 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1460 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1463 ModestMsgViewWindowPrivate *priv;
1464 GtkTreeIter tmp_iter;
1465 gboolean is_last_selected;
1467 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1468 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1470 /*if no model (so no rows at all), then virtually we are the last*/
1471 if (!priv->header_model)
1474 path = gtk_tree_row_reference_get_path (priv->row_reference);
1478 is_last_selected = TRUE;
1479 while (is_last_selected) {
1481 gtk_tree_path_next (path);
1482 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1484 gtk_tree_model_get (priv->header_model, &tmp_iter,
1485 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1487 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1488 is_last_selected = FALSE;
1490 gtk_tree_path_free (path);
1491 return is_last_selected;
1495 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1497 ModestMsgViewWindowPrivate *priv;
1499 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1500 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1502 return priv->header_model != NULL;
1506 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1508 ModestMsgViewWindowPrivate *priv;
1510 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1511 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1513 return priv->is_search_result;
1517 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1520 ModestMsgViewWindowPrivate *priv;
1521 gboolean is_first_selected;
1522 GtkTreeIter tmp_iter;
1523 /* gchar * path_string;*/
1525 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1526 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1528 /*if no model (so no rows at all), then virtually we are the first*/
1529 if (!priv->header_model)
1532 path = gtk_tree_row_reference_get_path (priv->row_reference);
1536 /* path_string = gtk_tree_path_to_string (path);
1537 is_first_selected = strcmp (path_string, "0");
1539 g_free (path_string);
1540 gtk_tree_path_free (path);
1542 return is_first_selected;*/
1544 is_first_selected = TRUE;
1545 while (is_first_selected) {
1547 if(!gtk_tree_path_prev (path))
1549 /* Here the 'if' is needless for logic, but let make sure
1550 * iter is valid for gtk_tree_model_get. */
1551 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1553 gtk_tree_model_get (priv->header_model, &tmp_iter,
1554 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1556 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1557 is_first_selected = FALSE;
1559 gtk_tree_path_free (path);
1560 return is_first_selected;
1564 * Reads the message whose summary item is @header. It takes care of
1565 * several things, among others:
1567 * If the message was not previously downloaded then ask the user
1568 * before downloading. If there is no connection launch the connection
1569 * dialog. Update toolbar dimming rules.
1571 * Returns: TRUE if the mail operation was started, otherwise if the
1572 * user do not want to download the message, or if the user do not
1573 * want to connect, then the operation is not issued
1576 message_reader (ModestMsgViewWindow *window,
1577 ModestMsgViewWindowPrivate *priv,
1579 GtkTreeRowReference *row_reference)
1581 ModestMailOperation *mail_op = NULL;
1582 ModestMailOperationTypeOperation op_type;
1583 gboolean already_showing = FALSE;
1584 ModestWindow *msg_window = NULL;
1585 ModestWindowMgr *mgr;
1587 g_return_val_if_fail (row_reference != NULL, FALSE);
1589 mgr = modest_runtime_get_window_mgr ();
1590 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1591 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1594 gtk_window_present (GTK_WINDOW (msg_window));
1595 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1599 /* Msg download completed */
1600 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1601 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1603 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1605 /* Ask the user if he wants to download the message if
1607 if (!tny_device_is_online (modest_runtime_get_device())) {
1608 TnyFolder *folder = NULL;
1609 GtkResponseType response;
1611 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1612 _("mcen_nc_get_msg"));
1613 if (response == GTK_RESPONSE_CANCEL)
1616 /* Offer the connection dialog if necessary */
1617 folder = tny_header_get_folder (header);
1619 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1620 TNY_FOLDER_STORE (folder))) {
1621 g_object_unref (folder);
1624 g_object_unref (folder);
1629 /* New mail operation */
1630 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1631 modest_ui_actions_get_msgs_full_error_handler,
1634 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1635 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1636 g_object_unref (mail_op);
1638 /* Update toolbar dimming rules */
1639 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1645 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1647 ModestMsgViewWindowPrivate *priv;
1648 GtkTreePath *path= NULL;
1649 GtkTreeIter tmp_iter;
1651 gboolean retval = TRUE;
1652 GtkTreeRowReference *row_reference = NULL;
1654 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1655 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1657 /* Update the next row reference if it's not valid. This could
1658 happen if for example the header which it was pointing to,
1659 was deleted. The best place to do it is in the row-deleted
1660 handler but the tinymail model do not work like the glib
1661 tree models and reports the deletion when the row is still
1663 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1664 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1665 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1666 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1669 if (priv->next_row_reference)
1670 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1674 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1676 gtk_tree_model_get_iter (priv->header_model,
1679 gtk_tree_path_free (path);
1681 gtk_tree_model_get (priv->header_model, &tmp_iter,
1682 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1685 /* Read the message & show it */
1686 if (!message_reader (window, priv, header, row_reference)) {
1688 gtk_tree_row_reference_free (row_reference);
1692 g_object_unref (header);
1698 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1700 ModestMsgViewWindowPrivate *priv = NULL;
1701 TnyHeader *header = NULL;
1703 GtkTreePath *path = NULL;
1704 GtkTreeRowReference *row_reference = NULL;
1706 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1707 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1709 /* Check that the model is not empty */
1710 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1713 /* Get the header */
1714 gtk_tree_model_get (priv->header_model,
1716 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1718 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1719 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1720 g_object_unref (header);
1721 return modest_msg_view_window_select_next_message (self);
1724 path = gtk_tree_model_get_path (priv->header_model, &iter);
1725 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1726 gtk_tree_path_free (path);
1728 /* Read the message & show it */
1729 message_reader (self, priv, header, row_reference);
1732 g_object_unref (header);
1738 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1740 ModestMsgViewWindowPrivate *priv = NULL;
1742 GtkTreeRowReference *row_reference = NULL;
1744 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1745 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1747 /* Return inmediatly if there is no header model */
1748 if (!priv->header_model)
1751 path = gtk_tree_row_reference_get_path (priv->row_reference);
1752 while (gtk_tree_path_prev (path)) {
1756 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1757 gtk_tree_model_get (priv->header_model, &iter,
1758 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1762 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1763 g_object_unref (header);
1767 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1768 /* Read the message & show it */
1769 if (!message_reader (window, priv, header, row_reference)) {
1770 gtk_tree_row_reference_free (row_reference);
1771 g_object_unref (header);
1775 gtk_tree_path_free (path);
1776 g_object_unref (header);
1781 gtk_tree_path_free (path);
1786 view_msg_cb (ModestMailOperation *mail_op,
1793 ModestMsgViewWindow *self = NULL;
1794 ModestMsgViewWindowPrivate *priv = NULL;
1795 GtkTreeRowReference *row_reference = NULL;
1797 /* If there was any error */
1798 row_reference = (GtkTreeRowReference *) user_data;
1799 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1800 gtk_tree_row_reference_free (row_reference);
1804 /* Get the window */
1805 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1806 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1807 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1809 /* Update the row reference */
1810 gtk_tree_row_reference_free (priv->row_reference);
1811 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1812 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1813 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1814 gtk_tree_row_reference_free (row_reference);
1816 /* Mark header as read */
1817 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1818 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1820 /* Set new message */
1821 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1822 modest_msg_view_window_update_priority (self);
1823 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1824 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1826 /* Set the new message uid of the window */
1827 if (priv->msg_uid) {
1828 g_free (priv->msg_uid);
1829 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1832 /* Notify the observers */
1833 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1834 0, priv->header_model, priv->row_reference);
1836 /* Free new references */
1837 g_object_unref (self);
1841 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1843 ModestMsgViewWindowPrivate *priv;
1845 TnyFolderType folder_type;
1847 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1849 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1851 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1855 folder = tny_msg_get_folder (msg);
1857 folder_type = tny_folder_get_folder_type (folder);
1858 g_object_unref (folder);
1860 g_object_unref (msg);
1868 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1870 ModestMsgViewWindowPrivate *priv;
1871 TnyHeaderFlags flags = 0;
1873 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1875 if (priv->header_model) {
1878 GtkTreePath *path = NULL;
1880 path = gtk_tree_row_reference_get_path (priv->row_reference);
1881 g_return_if_fail (path != NULL);
1882 gtk_tree_model_get_iter (priv->header_model,
1884 gtk_tree_row_reference_get_path (priv->row_reference));
1886 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1888 flags = tny_header_get_flags (header);
1889 gtk_tree_path_free (path);
1892 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1897 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1899 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1900 ModestWindowPrivate *parent_priv;
1901 ModestWindowMgr *mgr;
1902 gboolean is_fullscreen;
1903 GtkAction *fs_toggle_action;
1906 mgr = modest_runtime_get_window_mgr ();
1907 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1909 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1911 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1912 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1913 if (is_fullscreen != active) {
1914 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1923 set_homogeneous (GtkWidget *widget,
1926 if (GTK_IS_TOOL_ITEM (widget)) {
1927 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1928 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1933 modest_msg_view_window_show_toolbar (ModestWindow *self,
1934 gboolean show_toolbar)
1936 ModestMsgViewWindowPrivate *priv = NULL;
1937 ModestWindowPrivate *parent_priv;
1938 GtkWidget *reply_button = NULL, *menu = NULL;
1939 GtkWidget *placeholder = NULL;
1941 const gchar *action_name;
1944 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1945 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1947 /* Set optimized view status */
1948 priv->optimized_view = !show_toolbar;
1950 if (!parent_priv->toolbar) {
1951 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1953 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1955 /* Set homogeneous toolbar */
1956 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1957 set_homogeneous, NULL);
1959 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1960 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1961 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1962 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1963 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1964 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1965 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1966 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1968 /* Add ProgressBar (Transfer toolbar) */
1969 priv->progress_bar = modest_progress_bar_widget_new ();
1970 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1971 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1972 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1973 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1974 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1976 /* Connect cancel 'clicked' signal to abort progress mode */
1977 g_signal_connect(priv->cancel_toolitem, "clicked",
1978 G_CALLBACK(cancel_progressbar),
1981 /* Add it to the observers list */
1982 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1985 hildon_window_add_toolbar (HILDON_WINDOW (self),
1986 GTK_TOOLBAR (parent_priv->toolbar));
1989 /* Set reply button tap and hold menu */
1990 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1991 "/ToolBar/ToolbarMessageReply");
1992 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1993 "/ToolbarReplyCSM");
1994 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1998 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1999 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2000 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2002 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2003 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
2006 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2007 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2010 /* Update also the actions (to update the toggles in the
2011 menus), we have to do it manually because some other window
2012 of the same time could have changed it (remember that the
2013 toolbar fullscreen mode is shared by all the windows of the
2015 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2016 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2018 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2020 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2021 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2026 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2028 ModestMsgViewWindow *window)
2030 if (!GTK_WIDGET_VISIBLE (window))
2033 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2037 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2039 ModestMsgViewWindowPrivate *priv;
2041 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2042 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2044 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2048 cancel_progressbar (GtkToolButton *toolbutton,
2049 ModestMsgViewWindow *self)
2052 ModestMsgViewWindowPrivate *priv;
2054 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2056 /* Get operation observers and cancel its current operation */
2057 tmp = priv->progress_widgets;
2059 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2060 tmp=g_slist_next(tmp);
2064 observers_empty (ModestMsgViewWindow *self)
2067 ModestMsgViewWindowPrivate *priv;
2068 gboolean is_empty = TRUE;
2069 guint pending_ops = 0;
2071 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2072 tmp = priv->progress_widgets;
2074 /* Check all observers */
2075 while (tmp && is_empty) {
2076 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2077 is_empty = pending_ops == 0;
2079 tmp = g_slist_next(tmp);
2086 on_account_removed (TnyAccountStore *account_store,
2087 TnyAccount *account,
2090 /* Do nothing if it's a transport account, because we only
2091 show the messages of a store account */
2092 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2093 const gchar *parent_acc = NULL;
2094 const gchar *our_acc = NULL;
2096 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2097 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2099 /* Close this window if I'm showing a message of the removed account */
2100 if (strcmp (parent_acc, our_acc) == 0)
2101 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2106 on_queue_changed (ModestMailOperationQueue *queue,
2107 ModestMailOperation *mail_op,
2108 ModestMailOperationQueueNotification type,
2109 ModestMsgViewWindow *self)
2112 ModestMsgViewWindowPrivate *priv;
2113 ModestMailOperationTypeOperation op_type;
2114 ModestToolBarModes mode;
2116 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2117 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2119 /* If this operations was created by another window, do nothing */
2120 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2123 /* Get toolbar mode from operation id*/
2124 op_type = modest_mail_operation_get_type_operation (mail_op);
2126 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2127 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2128 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2129 mode = TOOLBAR_MODE_TRANSFER;
2132 mode = TOOLBAR_MODE_NORMAL;
2136 /* Add operation observers and change toolbar if neccessary*/
2137 tmp = priv->progress_widgets;
2139 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2140 if (mode == TOOLBAR_MODE_TRANSFER) {
2141 /* Enable transfer toolbar mode */
2142 set_toolbar_transfer_mode(self);
2144 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2146 tmp = g_slist_next (tmp);
2151 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2152 if (mode == TOOLBAR_MODE_TRANSFER) {
2154 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2156 tmp = g_slist_next (tmp);
2160 /* If no more operations are being observed, NORMAL mode is enabled again */
2161 if (observers_empty (self)) {
2162 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2170 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2172 ModestMsgViewWindowPrivate *priv;
2173 GList *selected_attachments = NULL;
2175 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2176 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2178 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2180 return selected_attachments;
2184 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2186 ModestMsgViewWindowPrivate *priv;
2187 const gchar *msg_uid;
2188 gchar *attachment_uid = NULL;
2189 gint attachment_index = 0;
2192 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2193 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2194 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2196 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2197 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2198 attachment_index = g_list_index (attachments, mime_part);
2199 g_list_free (attachments);
2201 if (msg_uid && attachment_index >= 0) {
2202 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2205 if (mime_part == NULL) {
2206 gboolean error = FALSE;
2207 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2208 if (selected_attachments == NULL) {
2210 } else if (g_list_length (selected_attachments) > 1) {
2211 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2214 mime_part = (TnyMimePart *) selected_attachments->data;
2215 g_object_ref (mime_part);
2217 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2218 g_list_free (selected_attachments);
2223 g_object_ref (mime_part);
2226 if (tny_mime_part_is_purged (mime_part)) {
2227 g_object_unref (mime_part);
2231 if (!TNY_IS_MSG (mime_part)) {
2232 gchar *filepath = NULL;
2233 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2234 TnyFsStream *temp_stream = NULL;
2235 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid,
2239 const gchar *content_type;
2240 content_type = tny_mime_part_get_content_type (mime_part);
2241 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2243 /* make the file read-only */
2244 if (g_chmod(filepath, 0444) != 0)
2245 g_warning ("%s: failed to set file '%s' to read-only: %s",
2246 __FUNCTION__, filepath, strerror(errno));
2248 modest_platform_activate_file (filepath, content_type);
2249 g_object_unref (temp_stream);
2251 /* NOTE: files in the temporary area will be automatically
2252 * cleaned after some time if they are no longer in use */
2255 /* message attachment */
2256 TnyHeader *header = NULL;
2257 ModestWindowMgr *mgr;
2258 ModestWindow *msg_win = NULL;
2261 header = tny_msg_get_header (TNY_MSG (mime_part));
2262 mgr = modest_runtime_get_window_mgr ();
2263 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2266 if (msg_win) /* there is already a window for this uid; top it */
2267 gtk_window_present (GTK_WINDOW(msg_win));
2269 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2270 * thus, we don't do anything */
2271 g_warning ("window for is already being created");
2273 /* it's not found, so create a new window for it */
2274 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2275 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2277 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2278 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2279 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2280 modest_window_get_zoom (MODEST_WINDOW (window)));
2281 modest_window_mgr_register_window (mgr, msg_win);
2282 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2283 gtk_widget_show_all (GTK_WIDGET (msg_win));
2286 g_object_unref (mime_part);
2302 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2303 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2304 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2305 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2308 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2312 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2313 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2314 g_free (pair->filename);
2315 g_object_unref (pair->part);
2316 g_slice_free (SaveMimePartPair, pair);
2318 g_list_free (info->pairs);
2321 gtk_widget_destroy (info->banner);
2322 g_object_unref (info->banner);
2323 g_slice_free (SaveMimePartInfo, info);
2328 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2330 if (info->pairs != NULL) {
2331 save_mime_part_to_file (info);
2334 result = info->result;
2336 /* This is a GDK lock because we are an idle callback and
2337 * hildon_banner_show_information is or does Gtk+ code */
2339 gdk_threads_enter (); /* CHECKED */
2340 save_mime_part_info_free (info, TRUE);
2342 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2344 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2346 gdk_threads_leave (); /* CHECKED */
2353 save_mime_part_to_file (SaveMimePartInfo *info)
2355 GnomeVFSResult result;
2356 GnomeVFSHandle *handle;
2358 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2360 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2361 if (result == GNOME_VFS_OK) {
2362 stream = tny_vfs_stream_new (handle);
2363 tny_mime_part_decode_to_stream (pair->part, stream);
2364 g_object_unref (G_OBJECT (stream));
2365 g_object_unref (pair->part);
2366 g_slice_free (SaveMimePartPair, pair);
2367 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2368 info->result = TRUE;
2370 save_mime_part_info_free (info, FALSE);
2371 info->result = FALSE;
2374 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2379 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2381 gboolean is_ok = TRUE;
2382 gint replaced_files = 0;
2383 const GList *files = info->pairs;
2386 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2387 SaveMimePartPair *pair = iter->data;
2388 if (modest_maemo_utils_file_exists (pair->filename)) {
2392 if (replaced_files) {
2393 GtkWidget *confirm_overwrite_dialog;
2394 const gchar *message = (replaced_files == 1) ?
2395 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2396 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2397 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2400 gtk_widget_destroy (confirm_overwrite_dialog);
2404 save_mime_part_info_free (info, TRUE);
2406 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2407 _CS("sfil_ib_saving"));
2408 info->banner = g_object_ref (banner);
2409 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2410 g_object_unref (banner);
2417 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2419 gboolean clean_list = FALSE;
2420 ModestMsgViewWindowPrivate *priv;
2421 GList *files_to_save = NULL;
2422 GtkWidget *save_dialog = NULL;
2423 gchar *folder = NULL;
2424 gboolean canceled = FALSE;
2425 const gchar *filename = NULL;
2426 gchar *save_multiple_str = NULL;
2428 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2429 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2431 if (mime_parts == NULL) {
2432 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2433 if (mime_parts == NULL)
2438 /* prepare dialog */
2439 if (mime_parts->next == NULL) {
2440 /* only one attachment selected */
2441 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2442 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2443 filename = tny_mime_part_get_filename (mime_part);
2445 g_warning ("Tried to save a non-file attachment");
2449 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2450 g_list_length (mime_parts));
2453 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2454 GTK_FILE_CHOOSER_ACTION_SAVE);
2457 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2458 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2462 if (filename != NULL)
2463 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2466 /* if multiple, set multiple string */
2467 if (save_multiple_str) {
2468 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2472 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2473 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2475 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2476 hildon_banner_show_information
2477 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2481 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2482 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2484 if (tny_mime_part_is_attachment (mime_part)) {
2485 SaveMimePartPair *pair;
2487 if ((mime_parts->next != NULL) &&
2488 (tny_mime_part_get_filename (mime_part) == NULL))
2491 pair = g_slice_new0 (SaveMimePartPair);
2492 if (mime_parts->next == NULL) {
2493 pair->filename = g_strdup (chooser_uri);
2496 g_build_filename (chooser_uri,
2497 tny_mime_part_get_filename (mime_part), NULL);
2499 pair->part = g_object_ref (mime_part);
2500 files_to_save = g_list_prepend (files_to_save, pair);
2504 g_free (chooser_uri);
2507 gtk_widget_destroy (save_dialog);
2510 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2511 g_list_free (mime_parts);
2514 if (files_to_save != NULL) {
2515 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2516 info->pairs = files_to_save;
2517 info->result = TRUE;
2518 save_mime_parts_to_file_with_checks (info);
2523 show_remove_attachment_information (gpointer userdata)
2525 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2526 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2528 /* We're outside the main lock */
2529 gdk_threads_enter ();
2531 if (priv->remove_attachment_banner != NULL) {
2532 gtk_widget_destroy (priv->remove_attachment_banner);
2533 g_object_unref (priv->remove_attachment_banner);
2536 priv->remove_attachment_banner = g_object_ref (
2537 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2539 gdk_threads_leave ();
2545 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2547 ModestMsgViewWindowPrivate *priv;
2548 GList *mime_parts = NULL, *node;
2549 gchar *confirmation_message;
2553 /* TnyFolder *folder; */
2555 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2556 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2559 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2561 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2563 /* Remove already purged messages from mime parts list */
2565 while (node != NULL) {
2566 TnyMimePart *part = TNY_MIME_PART (node->data);
2567 if (tny_mime_part_is_purged (part)) {
2568 GList *deleted_node = node;
2569 node = g_list_next (node);
2570 g_object_unref (part);
2571 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2573 node = g_list_next (node);
2577 if (mime_parts == NULL)
2580 n_attachments = g_list_length (mime_parts);
2581 if (n_attachments == 1) {
2582 const gchar *filename;
2584 if (TNY_IS_MSG (mime_parts->data)) {
2586 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2587 filename = tny_header_get_subject (header);
2588 g_object_unref (header);
2589 if (filename == NULL)
2590 filename = _("mail_va_no_subject");
2592 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2594 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2596 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2597 "mcen_nc_purge_files_text",
2598 n_attachments), n_attachments);
2600 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2601 confirmation_message);
2602 g_free (confirmation_message);
2604 if (response != GTK_RESPONSE_OK)
2607 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2608 /* folder = tny_msg_get_folder (msg); */
2609 /* tny_msg_uncache_attachments (msg); */
2610 /* tny_folder_refresh (folder, NULL); */
2611 /* g_object_unref (folder); */
2613 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2614 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2615 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2618 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2619 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2620 tny_msg_rewrite_cache (msg);
2621 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2623 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2624 g_list_free (mime_parts);
2626 if (priv->purge_timeout > 0) {
2627 g_source_remove (priv->purge_timeout);
2628 priv->purge_timeout = 0;
2631 if (priv->remove_attachment_banner) {
2632 gtk_widget_destroy (priv->remove_attachment_banner);
2633 g_object_unref (priv->remove_attachment_banner);
2634 priv->remove_attachment_banner = NULL;
2642 update_window_title (ModestMsgViewWindow *window)
2644 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2646 TnyHeader *header = NULL;
2647 const gchar *subject = NULL;
2649 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2652 header = tny_msg_get_header (msg);
2653 subject = tny_header_get_subject (header);
2654 g_object_unref (msg);
2657 if ((subject == NULL)||(subject[0] == '\0'))
2658 subject = _("mail_va_no_subject");
2660 gtk_window_set_title (GTK_WINDOW (window), subject);
2664 static void on_move_focus (ModestMsgViewWindow *window,
2665 GtkDirectionType direction,
2668 GtkWidget *current_focus = NULL;
2670 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2671 if ((current_focus != NULL) &&
2672 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2673 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");