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,
1488 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1489 is_last_selected = FALSE;
1490 g_object_unref(G_OBJECT(header));
1493 gtk_tree_path_free (path);
1494 return is_last_selected;
1498 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1500 ModestMsgViewWindowPrivate *priv;
1502 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1503 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1505 return priv->header_model != NULL;
1509 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1511 ModestMsgViewWindowPrivate *priv;
1513 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1514 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1516 return priv->is_search_result;
1520 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1523 ModestMsgViewWindowPrivate *priv;
1524 gboolean is_first_selected;
1525 GtkTreeIter tmp_iter;
1526 /* gchar * path_string;*/
1528 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1529 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1531 /*if no model (so no rows at all), then virtually we are the first*/
1532 if (!priv->header_model)
1535 path = gtk_tree_row_reference_get_path (priv->row_reference);
1539 /* path_string = gtk_tree_path_to_string (path);
1540 is_first_selected = strcmp (path_string, "0");
1542 g_free (path_string);
1543 gtk_tree_path_free (path);
1545 return is_first_selected;*/
1547 is_first_selected = TRUE;
1548 while (is_first_selected) {
1550 if(!gtk_tree_path_prev (path))
1552 /* Here the 'if' is needless for logic, but let make sure
1553 * iter is valid for gtk_tree_model_get. */
1554 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1556 gtk_tree_model_get (priv->header_model, &tmp_iter,
1557 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1560 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1561 is_first_selected = FALSE;
1562 g_object_unref(G_OBJECT(header));
1565 gtk_tree_path_free (path);
1566 return is_first_selected;
1570 * Reads the message whose summary item is @header. It takes care of
1571 * several things, among others:
1573 * If the message was not previously downloaded then ask the user
1574 * before downloading. If there is no connection launch the connection
1575 * dialog. Update toolbar dimming rules.
1577 * Returns: TRUE if the mail operation was started, otherwise if the
1578 * user do not want to download the message, or if the user do not
1579 * want to connect, then the operation is not issued
1582 message_reader (ModestMsgViewWindow *window,
1583 ModestMsgViewWindowPrivate *priv,
1585 GtkTreeRowReference *row_reference)
1587 ModestMailOperation *mail_op = NULL;
1588 ModestMailOperationTypeOperation op_type;
1589 gboolean already_showing = FALSE;
1590 ModestWindow *msg_window = NULL;
1591 ModestWindowMgr *mgr;
1593 g_return_val_if_fail (row_reference != NULL, FALSE);
1595 mgr = modest_runtime_get_window_mgr ();
1596 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1597 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1600 gtk_window_present (GTK_WINDOW (msg_window));
1601 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1605 /* Msg download completed */
1606 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1607 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1609 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1611 /* Ask the user if he wants to download the message if
1613 if (!tny_device_is_online (modest_runtime_get_device())) {
1614 TnyFolder *folder = NULL;
1615 GtkResponseType response;
1617 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1618 _("mcen_nc_get_msg"));
1619 if (response == GTK_RESPONSE_CANCEL)
1622 /* Offer the connection dialog if necessary */
1623 folder = tny_header_get_folder (header);
1625 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1626 TNY_FOLDER_STORE (folder))) {
1627 g_object_unref (folder);
1630 g_object_unref (folder);
1635 /* New mail operation */
1636 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1637 modest_ui_actions_get_msgs_full_error_handler,
1640 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1641 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1642 g_object_unref (mail_op);
1644 /* Update toolbar dimming rules */
1645 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1651 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1653 ModestMsgViewWindowPrivate *priv;
1654 GtkTreePath *path= NULL;
1655 GtkTreeIter tmp_iter;
1657 gboolean retval = TRUE;
1658 GtkTreeRowReference *row_reference = NULL;
1660 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1661 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1663 /* Update the next row reference if it's not valid. This could
1664 happen if for example the header which it was pointing to,
1665 was deleted. The best place to do it is in the row-deleted
1666 handler but the tinymail model do not work like the glib
1667 tree models and reports the deletion when the row is still
1669 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1670 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1671 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1672 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1675 if (priv->next_row_reference)
1676 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1680 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1682 gtk_tree_model_get_iter (priv->header_model,
1685 gtk_tree_path_free (path);
1687 gtk_tree_model_get (priv->header_model, &tmp_iter,
1688 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1691 /* Read the message & show it */
1692 if (!message_reader (window, priv, header, row_reference)) {
1694 gtk_tree_row_reference_free (row_reference);
1698 g_object_unref (header);
1704 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1706 ModestMsgViewWindowPrivate *priv = NULL;
1707 TnyHeader *header = NULL;
1709 GtkTreePath *path = NULL;
1710 GtkTreeRowReference *row_reference = NULL;
1712 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1713 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1715 /* Check that the model is not empty */
1716 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1719 /* Get the header */
1720 gtk_tree_model_get (priv->header_model,
1722 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1724 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1725 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1726 g_object_unref (header);
1727 return modest_msg_view_window_select_next_message (self);
1730 path = gtk_tree_model_get_path (priv->header_model, &iter);
1731 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1732 gtk_tree_path_free (path);
1734 /* Read the message & show it */
1735 message_reader (self, priv, header, row_reference);
1738 g_object_unref (header);
1744 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1746 ModestMsgViewWindowPrivate *priv = NULL;
1748 GtkTreeRowReference *row_reference = NULL;
1750 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1751 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1753 /* Return inmediatly if there is no header model */
1754 if (!priv->header_model)
1757 path = gtk_tree_row_reference_get_path (priv->row_reference);
1758 while (gtk_tree_path_prev (path)) {
1762 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1763 gtk_tree_model_get (priv->header_model, &iter,
1764 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1768 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1769 g_object_unref (header);
1773 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1774 /* Read the message & show it */
1775 if (!message_reader (window, priv, header, row_reference)) {
1776 gtk_tree_row_reference_free (row_reference);
1777 g_object_unref (header);
1781 gtk_tree_path_free (path);
1782 g_object_unref (header);
1787 gtk_tree_path_free (path);
1792 view_msg_cb (ModestMailOperation *mail_op,
1799 ModestMsgViewWindow *self = NULL;
1800 ModestMsgViewWindowPrivate *priv = NULL;
1801 GtkTreeRowReference *row_reference = NULL;
1803 /* If there was any error */
1804 row_reference = (GtkTreeRowReference *) user_data;
1805 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1806 gtk_tree_row_reference_free (row_reference);
1810 /* Get the window */
1811 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1812 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1813 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1815 /* Update the row reference */
1816 gtk_tree_row_reference_free (priv->row_reference);
1817 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1818 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1819 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1820 gtk_tree_row_reference_free (row_reference);
1822 /* Mark header as read */
1823 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1824 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1826 /* Set new message */
1827 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1828 modest_msg_view_window_update_priority (self);
1829 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1830 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1832 /* Set the new message uid of the window */
1833 if (priv->msg_uid) {
1834 g_free (priv->msg_uid);
1835 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1838 /* Notify the observers */
1839 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1840 0, priv->header_model, priv->row_reference);
1842 /* Free new references */
1843 g_object_unref (self);
1847 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1849 ModestMsgViewWindowPrivate *priv;
1851 TnyFolderType folder_type;
1853 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1855 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1857 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1861 folder = tny_msg_get_folder (msg);
1863 folder_type = tny_folder_get_folder_type (folder);
1864 g_object_unref (folder);
1866 g_object_unref (msg);
1874 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1876 ModestMsgViewWindowPrivate *priv;
1877 TnyHeaderFlags flags = 0;
1879 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1881 if (priv->header_model) {
1884 GtkTreePath *path = NULL;
1886 path = gtk_tree_row_reference_get_path (priv->row_reference);
1887 g_return_if_fail (path != NULL);
1888 gtk_tree_model_get_iter (priv->header_model,
1890 gtk_tree_row_reference_get_path (priv->row_reference));
1892 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1895 flags = tny_header_get_flags (header);
1896 g_object_unref(G_OBJECT(header));
1898 gtk_tree_path_free (path);
1901 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1906 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1908 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1909 ModestWindowPrivate *parent_priv;
1910 ModestWindowMgr *mgr;
1911 gboolean is_fullscreen;
1912 GtkAction *fs_toggle_action;
1915 mgr = modest_runtime_get_window_mgr ();
1916 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1918 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1920 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1921 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1922 if (is_fullscreen != active) {
1923 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1932 set_homogeneous (GtkWidget *widget,
1935 if (GTK_IS_TOOL_ITEM (widget)) {
1936 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1937 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1942 modest_msg_view_window_show_toolbar (ModestWindow *self,
1943 gboolean show_toolbar)
1945 ModestMsgViewWindowPrivate *priv = NULL;
1946 ModestWindowPrivate *parent_priv;
1947 GtkWidget *reply_button = NULL, *menu = NULL;
1948 GtkWidget *placeholder = NULL;
1950 const gchar *action_name;
1953 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1954 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1956 /* Set optimized view status */
1957 priv->optimized_view = !show_toolbar;
1959 if (!parent_priv->toolbar) {
1960 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1962 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1964 /* Set homogeneous toolbar */
1965 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1966 set_homogeneous, NULL);
1968 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1969 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1970 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1971 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1972 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1973 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1974 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1975 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1977 /* Add ProgressBar (Transfer toolbar) */
1978 priv->progress_bar = modest_progress_bar_widget_new ();
1979 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1980 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1981 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1982 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1983 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1985 /* Connect cancel 'clicked' signal to abort progress mode */
1986 g_signal_connect(priv->cancel_toolitem, "clicked",
1987 G_CALLBACK(cancel_progressbar),
1990 /* Add it to the observers list */
1991 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1994 hildon_window_add_toolbar (HILDON_WINDOW (self),
1995 GTK_TOOLBAR (parent_priv->toolbar));
1998 /* Set reply button tap and hold menu */
1999 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2000 "/ToolBar/ToolbarMessageReply");
2001 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2002 "/ToolbarReplyCSM");
2003 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2007 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2008 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2009 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2011 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2012 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
2015 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2016 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2019 /* Update also the actions (to update the toggles in the
2020 menus), we have to do it manually because some other window
2021 of the same time could have changed it (remember that the
2022 toolbar fullscreen mode is shared by all the windows of the
2024 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2025 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2027 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2029 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2030 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2035 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2037 ModestMsgViewWindow *window)
2039 if (!GTK_WIDGET_VISIBLE (window))
2042 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2046 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2048 ModestMsgViewWindowPrivate *priv;
2050 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2051 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2053 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2057 cancel_progressbar (GtkToolButton *toolbutton,
2058 ModestMsgViewWindow *self)
2061 ModestMsgViewWindowPrivate *priv;
2063 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2065 /* Get operation observers and cancel its current operation */
2066 tmp = priv->progress_widgets;
2068 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2069 tmp=g_slist_next(tmp);
2073 observers_empty (ModestMsgViewWindow *self)
2076 ModestMsgViewWindowPrivate *priv;
2077 gboolean is_empty = TRUE;
2078 guint pending_ops = 0;
2080 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2081 tmp = priv->progress_widgets;
2083 /* Check all observers */
2084 while (tmp && is_empty) {
2085 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2086 is_empty = pending_ops == 0;
2088 tmp = g_slist_next(tmp);
2095 on_account_removed (TnyAccountStore *account_store,
2096 TnyAccount *account,
2099 /* Do nothing if it's a transport account, because we only
2100 show the messages of a store account */
2101 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2102 const gchar *parent_acc = NULL;
2103 const gchar *our_acc = NULL;
2105 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2106 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2108 /* Close this window if I'm showing a message of the removed account */
2109 if (strcmp (parent_acc, our_acc) == 0)
2110 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2115 on_queue_changed (ModestMailOperationQueue *queue,
2116 ModestMailOperation *mail_op,
2117 ModestMailOperationQueueNotification type,
2118 ModestMsgViewWindow *self)
2121 ModestMsgViewWindowPrivate *priv;
2122 ModestMailOperationTypeOperation op_type;
2123 ModestToolBarModes mode;
2125 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2126 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2128 /* If this operations was created by another window, do nothing */
2129 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2132 /* Get toolbar mode from operation id*/
2133 op_type = modest_mail_operation_get_type_operation (mail_op);
2135 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2136 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2137 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2138 mode = TOOLBAR_MODE_TRANSFER;
2141 mode = TOOLBAR_MODE_NORMAL;
2145 /* Add operation observers and change toolbar if neccessary*/
2146 tmp = priv->progress_widgets;
2148 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2149 if (mode == TOOLBAR_MODE_TRANSFER) {
2150 /* Enable transfer toolbar mode */
2151 set_toolbar_transfer_mode(self);
2153 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2155 tmp = g_slist_next (tmp);
2160 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2161 if (mode == TOOLBAR_MODE_TRANSFER) {
2163 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2165 tmp = g_slist_next (tmp);
2169 /* If no more operations are being observed, NORMAL mode is enabled again */
2170 if (observers_empty (self)) {
2171 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2179 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2181 ModestMsgViewWindowPrivate *priv;
2182 GList *selected_attachments = NULL;
2184 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2185 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2187 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2189 return selected_attachments;
2193 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2195 ModestMsgViewWindowPrivate *priv;
2196 const gchar *msg_uid;
2197 gchar *attachment_uid = NULL;
2198 gint attachment_index = 0;
2201 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2202 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2203 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2205 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2206 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2207 attachment_index = g_list_index (attachments, mime_part);
2208 g_list_free (attachments);
2210 if (msg_uid && attachment_index >= 0) {
2211 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2214 if (mime_part == NULL) {
2215 gboolean error = FALSE;
2216 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2217 if (selected_attachments == NULL) {
2219 } else if (g_list_length (selected_attachments) > 1) {
2220 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2223 mime_part = (TnyMimePart *) selected_attachments->data;
2224 g_object_ref (mime_part);
2226 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2227 g_list_free (selected_attachments);
2232 g_object_ref (mime_part);
2235 if (tny_mime_part_is_purged (mime_part)) {
2236 g_object_unref (mime_part);
2240 if (!TNY_IS_MSG (mime_part)) {
2241 gchar *filepath = NULL;
2242 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2243 TnyFsStream *temp_stream = NULL;
2244 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid,
2248 const gchar *content_type;
2249 content_type = tny_mime_part_get_content_type (mime_part);
2250 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2252 /* make the file read-only */
2253 if (g_chmod(filepath, 0444) != 0)
2254 g_warning ("%s: failed to set file '%s' to read-only: %s",
2255 __FUNCTION__, filepath, strerror(errno));
2257 modest_platform_activate_file (filepath, content_type);
2258 g_object_unref (temp_stream);
2260 /* NOTE: files in the temporary area will be automatically
2261 * cleaned after some time if they are no longer in use */
2264 /* message attachment */
2265 TnyHeader *header = NULL;
2266 ModestWindowMgr *mgr;
2267 ModestWindow *msg_win = NULL;
2270 header = tny_msg_get_header (TNY_MSG (mime_part));
2271 mgr = modest_runtime_get_window_mgr ();
2272 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2275 if (msg_win) /* there is already a window for this uid; top it */
2276 gtk_window_present (GTK_WINDOW(msg_win));
2278 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2279 * thus, we don't do anything */
2280 g_warning ("window for is already being created");
2282 /* it's not found, so create a new window for it */
2283 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2284 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2286 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2287 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2288 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2289 modest_window_get_zoom (MODEST_WINDOW (window)));
2290 modest_window_mgr_register_window (mgr, msg_win);
2291 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2292 gtk_widget_show_all (GTK_WIDGET (msg_win));
2295 g_object_unref (mime_part);
2311 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2312 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2313 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2314 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2317 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2321 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2322 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2323 g_free (pair->filename);
2324 g_object_unref (pair->part);
2325 g_slice_free (SaveMimePartPair, pair);
2327 g_list_free (info->pairs);
2330 gtk_widget_destroy (info->banner);
2331 g_object_unref (info->banner);
2332 g_slice_free (SaveMimePartInfo, info);
2337 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2339 if (info->pairs != NULL) {
2340 save_mime_part_to_file (info);
2343 result = info->result;
2345 /* This is a GDK lock because we are an idle callback and
2346 * hildon_banner_show_information is or does Gtk+ code */
2348 gdk_threads_enter (); /* CHECKED */
2349 save_mime_part_info_free (info, TRUE);
2351 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2353 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2355 gdk_threads_leave (); /* CHECKED */
2362 save_mime_part_to_file (SaveMimePartInfo *info)
2364 GnomeVFSResult result;
2365 GnomeVFSHandle *handle;
2367 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2369 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2370 if (result == GNOME_VFS_OK) {
2371 stream = tny_vfs_stream_new (handle);
2372 tny_mime_part_decode_to_stream (pair->part, stream);
2373 g_object_unref (G_OBJECT (stream));
2374 g_object_unref (pair->part);
2375 g_slice_free (SaveMimePartPair, pair);
2376 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2377 info->result = TRUE;
2379 save_mime_part_info_free (info, FALSE);
2380 info->result = FALSE;
2383 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2388 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2390 gboolean is_ok = TRUE;
2391 gint replaced_files = 0;
2392 const GList *files = info->pairs;
2395 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2396 SaveMimePartPair *pair = iter->data;
2397 if (modest_maemo_utils_file_exists (pair->filename)) {
2401 if (replaced_files) {
2402 GtkWidget *confirm_overwrite_dialog;
2403 const gchar *message = (replaced_files == 1) ?
2404 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2405 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2406 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2409 gtk_widget_destroy (confirm_overwrite_dialog);
2413 save_mime_part_info_free (info, TRUE);
2415 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2416 _CS("sfil_ib_saving"));
2417 info->banner = g_object_ref (banner);
2418 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2419 g_object_unref (banner);
2426 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2428 gboolean clean_list = FALSE;
2429 ModestMsgViewWindowPrivate *priv;
2430 GList *files_to_save = NULL;
2431 GtkWidget *save_dialog = NULL;
2432 gchar *folder = NULL;
2433 gboolean canceled = FALSE;
2434 const gchar *filename = NULL;
2435 gchar *save_multiple_str = NULL;
2437 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2438 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2440 if (mime_parts == NULL) {
2441 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2442 if (mime_parts == NULL)
2447 /* prepare dialog */
2448 if (mime_parts->next == NULL) {
2449 /* only one attachment selected */
2450 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2451 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2452 filename = tny_mime_part_get_filename (mime_part);
2454 g_warning ("Tried to save a non-file attachment");
2458 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2459 g_list_length (mime_parts));
2462 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2463 GTK_FILE_CHOOSER_ACTION_SAVE);
2466 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2467 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2471 if (filename != NULL)
2472 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2475 /* if multiple, set multiple string */
2476 if (save_multiple_str) {
2477 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2481 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2482 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2484 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2485 hildon_banner_show_information
2486 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2490 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2491 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2493 if (tny_mime_part_is_attachment (mime_part)) {
2494 SaveMimePartPair *pair;
2496 if ((mime_parts->next != NULL) &&
2497 (tny_mime_part_get_filename (mime_part) == NULL))
2500 pair = g_slice_new0 (SaveMimePartPair);
2501 if (mime_parts->next == NULL) {
2502 pair->filename = g_strdup (chooser_uri);
2505 g_build_filename (chooser_uri,
2506 tny_mime_part_get_filename (mime_part), NULL);
2508 pair->part = g_object_ref (mime_part);
2509 files_to_save = g_list_prepend (files_to_save, pair);
2513 g_free (chooser_uri);
2516 gtk_widget_destroy (save_dialog);
2519 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2520 g_list_free (mime_parts);
2523 if (files_to_save != NULL) {
2524 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2525 info->pairs = files_to_save;
2526 info->result = TRUE;
2527 save_mime_parts_to_file_with_checks (info);
2532 show_remove_attachment_information (gpointer userdata)
2534 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2535 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2537 /* We're outside the main lock */
2538 gdk_threads_enter ();
2540 if (priv->remove_attachment_banner != NULL) {
2541 gtk_widget_destroy (priv->remove_attachment_banner);
2542 g_object_unref (priv->remove_attachment_banner);
2545 priv->remove_attachment_banner = g_object_ref (
2546 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2548 gdk_threads_leave ();
2554 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2556 ModestMsgViewWindowPrivate *priv;
2557 GList *mime_parts = NULL, *node;
2558 gchar *confirmation_message;
2562 /* TnyFolder *folder; */
2564 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2565 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2568 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2570 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2572 /* Remove already purged messages from mime parts list */
2574 while (node != NULL) {
2575 TnyMimePart *part = TNY_MIME_PART (node->data);
2576 if (tny_mime_part_is_purged (part)) {
2577 GList *deleted_node = node;
2578 node = g_list_next (node);
2579 g_object_unref (part);
2580 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2582 node = g_list_next (node);
2586 if (mime_parts == NULL)
2589 n_attachments = g_list_length (mime_parts);
2590 if (n_attachments == 1) {
2591 const gchar *filename;
2593 if (TNY_IS_MSG (mime_parts->data)) {
2595 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2596 filename = tny_header_get_subject (header);
2597 g_object_unref (header);
2598 if (filename == NULL)
2599 filename = _("mail_va_no_subject");
2601 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2603 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2605 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2606 "mcen_nc_purge_files_text",
2607 n_attachments), n_attachments);
2609 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2610 confirmation_message);
2611 g_free (confirmation_message);
2613 if (response != GTK_RESPONSE_OK)
2616 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2617 /* folder = tny_msg_get_folder (msg); */
2618 /* tny_msg_uncache_attachments (msg); */
2619 /* tny_folder_refresh (folder, NULL); */
2620 /* g_object_unref (folder); */
2622 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2623 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2624 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2627 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2628 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2629 tny_msg_rewrite_cache (msg);
2630 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2632 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2633 g_list_free (mime_parts);
2635 if (priv->purge_timeout > 0) {
2636 g_source_remove (priv->purge_timeout);
2637 priv->purge_timeout = 0;
2640 if (priv->remove_attachment_banner) {
2641 gtk_widget_destroy (priv->remove_attachment_banner);
2642 g_object_unref (priv->remove_attachment_banner);
2643 priv->remove_attachment_banner = NULL;
2651 update_window_title (ModestMsgViewWindow *window)
2653 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2655 TnyHeader *header = NULL;
2656 const gchar *subject = NULL;
2658 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2661 header = tny_msg_get_header (msg);
2662 subject = tny_header_get_subject (header);
2663 g_object_unref (msg);
2666 if ((subject == NULL)||(subject[0] == '\0'))
2667 subject = _("mail_va_no_subject");
2669 gtk_window_set_title (GTK_WINDOW (window), subject);
2673 static void on_move_focus (ModestMsgViewWindow *window,
2674 GtkDirectionType direction,
2677 GtkWidget *current_focus = NULL;
2679 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2680 if ((current_focus != NULL) &&
2681 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2682 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");