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 g_object_unref(G_OBJECT(header));
1045 if(!g_str_equal(priv->msg_uid, uid)){
1051 /* Setup row_reference for the actual msg. */
1052 priv->row_reference = gtk_tree_row_reference_new(
1053 new_model, tree_path);
1054 if(priv->row_reference == NULL){
1055 g_warning("No reference for msg header item.");
1059 /* Attach new_model and connect some callback to it to become able
1060 * to detect changes in header-view. */
1061 priv->header_model = g_object_ref(new_model);
1062 g_signal_connect (new_model, "row-changed",
1063 G_CALLBACK (modest_msg_view_window_on_row_changed),
1065 g_signal_connect (new_model, "row-deleted",
1066 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1068 g_signal_connect (new_model, "rows-reordered",
1069 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1072 /* Now set up next_row_reference. */
1073 priv->next_row_reference = gtk_tree_row_reference_copy(
1074 priv->row_reference);
1075 select_next_valid_row (priv->header_model,
1076 &(priv->next_row_reference), FALSE);
1078 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1081 void modest_msg_view_window_on_row_reordered(
1082 GtkTreeModel *header_model,
1086 ModestMsgViewWindow *window){
1087 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1090 /* The modest_msg_view_window_update_model_replaced implements update
1091 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1092 * actually belongs to the header-view is the same as the TnyFolder of
1093 * the message of msg-view or not. If they are different, there is
1094 * nothing to do. If they are the same, then the model has replaced and
1095 * the reference in msg-view shall be replaced from the old model to
1096 * the new model. In this case the view will be detached from it's
1097 * header folder. From this point the next/prev buttons are dimmed.
1099 void modest_msg_view_window_update_model_replaced(
1100 ModestHeaderViewObserver *observer,
1101 GtkTreeModel *model,
1102 const gchar *tny_folder_id){
1103 ModestMsgViewWindowPrivate *priv = NULL;
1104 ModestMsgViewWindow *window = NULL;
1106 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1107 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1109 window = MODEST_MSG_VIEW_WINDOW(observer);
1110 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1112 /* If there is an other folder in the header-view then we do
1113 * not care about it's model (msg list). Else if the
1114 * header-view shows the folder the msg shown by us is in, we
1115 * shall replace our model reference and make some check. */
1116 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1119 /* Model is changed(replaced), so we should forget the old
1120 * one. Because there might be other references and there
1121 * might be some change on the model even if we unreferenced
1122 * it, we need to disconnect our signals here. */
1123 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1124 priv->row_changed_handler))
1125 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1126 priv->row_changed_handler);
1127 priv->row_changed_handler = 0;
1128 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1129 priv->row_deleted_handler))
1130 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1131 priv->row_deleted_handler);
1132 priv->row_deleted_handler = 0;
1133 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1134 priv->row_inserted_handler))
1135 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1136 priv->row_inserted_handler);
1137 priv->row_inserted_handler = 0;
1138 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1139 priv->rows_reordered_handler))
1140 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1141 priv->rows_reordered_handler);
1142 priv->rows_reordered_handler = 0;
1143 g_object_unref(priv->header_model);
1144 priv->header_model = NULL;
1145 g_object_unref(priv->row_reference);
1146 priv->row_reference = NULL;
1147 g_object_unref(priv->next_row_reference);
1148 priv->next_row_reference = NULL;
1150 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1152 g_assert(model != NULL);
1154 /* Also we must connect to the new model for row insertions.
1155 * Only for insertions now. We will need other ones only after
1156 * the msg is show by msg-view is added to the new model. */
1157 priv->row_inserted_handler = g_signal_connect (
1158 model, "row-inserted",
1159 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1164 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1166 ModestMsgViewWindowPrivate *priv= NULL;
1168 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1169 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1171 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1175 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1177 ModestMsgViewWindowPrivate *priv= NULL;
1179 TnyHeader *header = NULL;
1180 GtkTreePath *path = NULL;
1183 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1184 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1186 /* If the message was not obtained from a treemodel,
1187 * for instance if it was opened directly by the search UI:
1189 if (priv->header_model == NULL) {
1190 msg = modest_msg_view_window_get_message (self);
1192 header = tny_msg_get_header (msg);
1193 g_object_unref (msg);
1198 /* Get iter of the currently selected message in the header view: */
1199 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1200 * instead of sometimes retrieving it from the header view?
1201 * Then we wouldn't be dependent on the message actually still being selected
1202 * in the header view. murrayc. */
1203 if (!gtk_tree_row_reference_valid (priv->row_reference))
1205 path = gtk_tree_row_reference_get_path (priv->row_reference);
1206 g_return_val_if_fail (path != NULL, NULL);
1207 gtk_tree_model_get_iter (priv->header_model,
1211 /* Get current message header */
1212 gtk_tree_model_get (priv->header_model, &iter,
1213 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1216 gtk_tree_path_free (path);
1221 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1223 ModestMsgViewWindowPrivate *priv;
1225 g_return_val_if_fail (self, NULL);
1227 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1229 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1233 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1235 ModestMsgViewWindowPrivate *priv;
1237 g_return_val_if_fail (self, NULL);
1239 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1241 return (const gchar*) priv->msg_uid;
1245 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1248 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1249 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1250 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1254 is_active = gtk_toggle_action_get_active (toggle);
1257 gtk_widget_show (priv->find_toolbar);
1258 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1260 gtk_widget_hide (priv->find_toolbar);
1263 /* update the toggle buttons status */
1264 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1265 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1266 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1267 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1272 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1273 ModestMsgViewWindow *obj)
1275 GtkToggleAction *toggle;
1276 ModestWindowPrivate *parent_priv;
1277 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1279 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1280 gtk_toggle_action_set_active (toggle, FALSE);
1284 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1285 ModestMsgViewWindow *obj)
1287 gchar *current_search;
1288 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1290 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1291 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1295 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1297 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1298 g_free (current_search);
1299 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1303 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1305 g_free (priv->last_search);
1306 priv->last_search = g_strdup (current_search);
1307 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1310 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1311 g_free (priv->last_search);
1312 priv->last_search = NULL;
1314 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1317 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1318 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1319 g_free (priv->last_search);
1320 priv->last_search = NULL;
1322 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1326 g_free (current_search);
1331 modest_msg_view_window_set_zoom (ModestWindow *window,
1334 ModestMsgViewWindowPrivate *priv;
1335 ModestWindowPrivate *parent_priv;
1336 GtkAction *action = NULL;
1337 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1339 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1341 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1342 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1343 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1345 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1346 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1348 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1352 modest_msg_view_window_get_zoom (ModestWindow *window)
1354 ModestMsgViewWindowPrivate *priv;
1356 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1358 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1359 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1363 modest_msg_view_window_zoom_plus (ModestWindow *window)
1365 ModestWindowPrivate *parent_priv;
1366 GtkRadioAction *zoom_radio_action;
1367 GSList *group, *node;
1369 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1370 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1371 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1373 group = gtk_radio_action_get_group (zoom_radio_action);
1375 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1376 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1380 for (node = group; node != NULL; node = g_slist_next (node)) {
1381 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1382 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1390 modest_msg_view_window_zoom_minus (ModestWindow *window)
1392 ModestWindowPrivate *parent_priv;
1393 GtkRadioAction *zoom_radio_action;
1394 GSList *group, *node;
1396 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1397 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1398 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1400 group = gtk_radio_action_get_group (zoom_radio_action);
1402 for (node = group; node != NULL; node = g_slist_next (node)) {
1403 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1404 if (node->next != NULL) {
1405 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1408 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1418 modest_msg_view_window_key_release_event (GtkWidget *window,
1422 if (event->type == GDK_KEY_RELEASE) {
1423 switch (event->keyval) {
1425 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1429 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1442 modest_msg_view_window_scroll_up (ModestWindow *window)
1444 ModestMsgViewWindowPrivate *priv;
1445 gboolean return_value;
1447 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1448 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1452 modest_msg_view_window_scroll_down (ModestWindow *window)
1454 ModestMsgViewWindowPrivate *priv;
1455 gboolean return_value;
1457 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1458 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1462 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1465 ModestMsgViewWindowPrivate *priv;
1466 GtkTreeIter tmp_iter;
1467 gboolean is_last_selected;
1469 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1470 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1472 /*if no model (so no rows at all), then virtually we are the last*/
1473 if (!priv->header_model)
1476 path = gtk_tree_row_reference_get_path (priv->row_reference);
1480 is_last_selected = TRUE;
1481 while (is_last_selected) {
1483 gtk_tree_path_next (path);
1484 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1486 gtk_tree_model_get (priv->header_model, &tmp_iter,
1487 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1490 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1491 is_last_selected = FALSE;
1492 g_object_unref(G_OBJECT(header));
1495 gtk_tree_path_free (path);
1496 return is_last_selected;
1500 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1502 ModestMsgViewWindowPrivate *priv;
1504 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1505 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1507 return priv->header_model != NULL;
1511 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1513 ModestMsgViewWindowPrivate *priv;
1515 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1516 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1518 return priv->is_search_result;
1522 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1525 ModestMsgViewWindowPrivate *priv;
1526 gboolean is_first_selected;
1527 GtkTreeIter tmp_iter;
1528 /* gchar * path_string;*/
1530 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1531 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1533 /*if no model (so no rows at all), then virtually we are the first*/
1534 if (!priv->header_model)
1537 path = gtk_tree_row_reference_get_path (priv->row_reference);
1541 /* path_string = gtk_tree_path_to_string (path);
1542 is_first_selected = strcmp (path_string, "0");
1544 g_free (path_string);
1545 gtk_tree_path_free (path);
1547 return is_first_selected;*/
1549 is_first_selected = TRUE;
1550 while (is_first_selected) {
1552 if(!gtk_tree_path_prev (path))
1554 /* Here the 'if' is needless for logic, but let make sure
1555 * iter is valid for gtk_tree_model_get. */
1556 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1558 gtk_tree_model_get (priv->header_model, &tmp_iter,
1559 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1562 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1563 is_first_selected = FALSE;
1564 g_object_unref(G_OBJECT(header));
1567 gtk_tree_path_free (path);
1568 return is_first_selected;
1572 * Reads the message whose summary item is @header. It takes care of
1573 * several things, among others:
1575 * If the message was not previously downloaded then ask the user
1576 * before downloading. If there is no connection launch the connection
1577 * dialog. Update toolbar dimming rules.
1579 * Returns: TRUE if the mail operation was started, otherwise if the
1580 * user do not want to download the message, or if the user do not
1581 * want to connect, then the operation is not issued
1584 message_reader (ModestMsgViewWindow *window,
1585 ModestMsgViewWindowPrivate *priv,
1587 GtkTreeRowReference *row_reference)
1589 ModestMailOperation *mail_op = NULL;
1590 ModestMailOperationTypeOperation op_type;
1591 gboolean already_showing = FALSE;
1592 ModestWindow *msg_window = NULL;
1593 ModestWindowMgr *mgr;
1595 g_return_val_if_fail (row_reference != NULL, FALSE);
1597 mgr = modest_runtime_get_window_mgr ();
1598 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1599 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1602 gtk_window_present (GTK_WINDOW (msg_window));
1603 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1607 /* Msg download completed */
1608 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1609 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1611 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1613 /* Ask the user if he wants to download the message if
1615 if (!tny_device_is_online (modest_runtime_get_device())) {
1616 TnyFolder *folder = NULL;
1617 GtkResponseType response;
1619 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1620 _("mcen_nc_get_msg"));
1621 if (response == GTK_RESPONSE_CANCEL)
1624 /* Offer the connection dialog if necessary */
1625 folder = tny_header_get_folder (header);
1627 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1628 TNY_FOLDER_STORE (folder))) {
1629 g_object_unref (folder);
1632 g_object_unref (folder);
1637 /* New mail operation */
1638 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1639 modest_ui_actions_get_msgs_full_error_handler,
1642 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1643 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1644 g_object_unref (mail_op);
1646 /* Update toolbar dimming rules */
1647 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1653 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1655 ModestMsgViewWindowPrivate *priv;
1656 GtkTreePath *path= NULL;
1657 GtkTreeIter tmp_iter;
1659 gboolean retval = TRUE;
1660 GtkTreeRowReference *row_reference = NULL;
1662 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1663 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1665 /* Update the next row reference if it's not valid. This could
1666 happen if for example the header which it was pointing to,
1667 was deleted. The best place to do it is in the row-deleted
1668 handler but the tinymail model do not work like the glib
1669 tree models and reports the deletion when the row is still
1671 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1672 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1673 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1674 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1677 if (priv->next_row_reference)
1678 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1682 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1684 gtk_tree_model_get_iter (priv->header_model,
1687 gtk_tree_path_free (path);
1689 gtk_tree_model_get (priv->header_model, &tmp_iter,
1690 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1693 /* Read the message & show it */
1694 if (!message_reader (window, priv, header, row_reference)) {
1696 gtk_tree_row_reference_free (row_reference);
1700 g_object_unref (header);
1706 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1708 ModestMsgViewWindowPrivate *priv = NULL;
1709 TnyHeader *header = NULL;
1711 GtkTreePath *path = NULL;
1712 GtkTreeRowReference *row_reference = NULL;
1714 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1715 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1717 /* Check that the model is not empty */
1718 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1721 /* Get the header */
1722 gtk_tree_model_get (priv->header_model,
1724 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1726 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1727 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1728 g_object_unref (header);
1729 return modest_msg_view_window_select_next_message (self);
1732 path = gtk_tree_model_get_path (priv->header_model, &iter);
1733 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1734 gtk_tree_path_free (path);
1736 /* Read the message & show it */
1737 message_reader (self, priv, header, row_reference);
1740 g_object_unref (header);
1746 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1748 ModestMsgViewWindowPrivate *priv = NULL;
1750 GtkTreeRowReference *row_reference = NULL;
1752 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1753 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1755 /* Return inmediatly if there is no header model */
1756 if (!priv->header_model)
1759 path = gtk_tree_row_reference_get_path (priv->row_reference);
1760 while (gtk_tree_path_prev (path)) {
1764 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1765 gtk_tree_model_get (priv->header_model, &iter,
1766 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1770 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1771 g_object_unref (header);
1775 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1776 /* Read the message & show it */
1777 if (!message_reader (window, priv, header, row_reference)) {
1778 gtk_tree_row_reference_free (row_reference);
1779 g_object_unref (header);
1783 gtk_tree_path_free (path);
1784 g_object_unref (header);
1789 gtk_tree_path_free (path);
1794 view_msg_cb (ModestMailOperation *mail_op,
1801 ModestMsgViewWindow *self = NULL;
1802 ModestMsgViewWindowPrivate *priv = NULL;
1803 GtkTreeRowReference *row_reference = NULL;
1805 /* If there was any error */
1806 row_reference = (GtkTreeRowReference *) user_data;
1807 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1808 gtk_tree_row_reference_free (row_reference);
1812 /* Get the window */
1813 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1814 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1815 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1817 /* Update the row reference */
1818 gtk_tree_row_reference_free (priv->row_reference);
1819 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1820 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1821 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1822 gtk_tree_row_reference_free (row_reference);
1824 /* Mark header as read */
1825 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1826 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1828 /* Set new message */
1829 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1830 modest_msg_view_window_update_priority (self);
1831 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1832 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1834 /* Set the new message uid of the window */
1835 if (priv->msg_uid) {
1836 g_free (priv->msg_uid);
1837 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1840 /* Notify the observers */
1841 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1842 0, priv->header_model, priv->row_reference);
1844 /* Free new references */
1845 g_object_unref (self);
1849 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1851 ModestMsgViewWindowPrivate *priv;
1853 TnyFolderType folder_type;
1855 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1857 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1859 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1863 folder = tny_msg_get_folder (msg);
1865 folder_type = tny_folder_get_folder_type (folder);
1866 g_object_unref (folder);
1868 g_object_unref (msg);
1876 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1878 ModestMsgViewWindowPrivate *priv;
1879 TnyHeaderFlags flags = 0;
1881 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1883 if (priv->header_model) {
1886 GtkTreePath *path = NULL;
1888 path = gtk_tree_row_reference_get_path (priv->row_reference);
1889 g_return_if_fail (path != NULL);
1890 gtk_tree_model_get_iter (priv->header_model,
1892 gtk_tree_row_reference_get_path (priv->row_reference));
1894 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1897 flags = tny_header_get_flags (header);
1898 g_object_unref(G_OBJECT(header));
1900 gtk_tree_path_free (path);
1903 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1908 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1910 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1911 ModestWindowPrivate *parent_priv;
1912 ModestWindowMgr *mgr;
1913 gboolean is_fullscreen;
1914 GtkAction *fs_toggle_action;
1917 mgr = modest_runtime_get_window_mgr ();
1918 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1920 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1922 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1923 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1924 if (is_fullscreen != active) {
1925 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1934 set_homogeneous (GtkWidget *widget,
1937 if (GTK_IS_TOOL_ITEM (widget)) {
1938 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1939 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1944 modest_msg_view_window_show_toolbar (ModestWindow *self,
1945 gboolean show_toolbar)
1947 ModestMsgViewWindowPrivate *priv = NULL;
1948 ModestWindowPrivate *parent_priv;
1949 GtkWidget *reply_button = NULL, *menu = NULL;
1950 GtkWidget *placeholder = NULL;
1952 const gchar *action_name;
1955 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1956 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1958 /* Set optimized view status */
1959 priv->optimized_view = !show_toolbar;
1961 if (!parent_priv->toolbar) {
1962 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1964 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1966 /* Set homogeneous toolbar */
1967 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1968 set_homogeneous, NULL);
1970 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1971 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1972 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1973 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1974 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1975 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1976 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1977 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1979 /* Add ProgressBar (Transfer toolbar) */
1980 priv->progress_bar = modest_progress_bar_widget_new ();
1981 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1982 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1983 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1984 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1985 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1987 /* Connect cancel 'clicked' signal to abort progress mode */
1988 g_signal_connect(priv->cancel_toolitem, "clicked",
1989 G_CALLBACK(cancel_progressbar),
1992 /* Add it to the observers list */
1993 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1996 hildon_window_add_toolbar (HILDON_WINDOW (self),
1997 GTK_TOOLBAR (parent_priv->toolbar));
2000 /* Set reply button tap and hold menu */
2001 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2002 "/ToolBar/ToolbarMessageReply");
2003 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2004 "/ToolbarReplyCSM");
2005 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2009 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2010 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2011 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2013 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2014 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2015 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2017 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2020 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2021 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2024 /* Update also the actions (to update the toggles in the
2025 menus), we have to do it manually because some other window
2026 of the same time could have changed it (remember that the
2027 toolbar fullscreen mode is shared by all the windows of the
2029 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2030 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2032 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2034 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2035 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2040 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2042 ModestMsgViewWindow *window)
2044 if (!GTK_WIDGET_VISIBLE (window))
2047 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2051 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2053 ModestMsgViewWindowPrivate *priv;
2055 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2056 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2058 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2062 cancel_progressbar (GtkToolButton *toolbutton,
2063 ModestMsgViewWindow *self)
2066 ModestMsgViewWindowPrivate *priv;
2068 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2070 /* Get operation observers and cancel its current operation */
2071 tmp = priv->progress_widgets;
2073 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2074 tmp=g_slist_next(tmp);
2078 observers_empty (ModestMsgViewWindow *self)
2081 ModestMsgViewWindowPrivate *priv;
2082 gboolean is_empty = TRUE;
2083 guint pending_ops = 0;
2085 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2086 tmp = priv->progress_widgets;
2088 /* Check all observers */
2089 while (tmp && is_empty) {
2090 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2091 is_empty = pending_ops == 0;
2093 tmp = g_slist_next(tmp);
2100 on_account_removed (TnyAccountStore *account_store,
2101 TnyAccount *account,
2104 /* Do nothing if it's a transport account, because we only
2105 show the messages of a store account */
2106 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2107 const gchar *parent_acc = NULL;
2108 const gchar *our_acc = NULL;
2110 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2111 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2113 /* Close this window if I'm showing a message of the removed account */
2114 if (strcmp (parent_acc, our_acc) == 0)
2115 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2120 on_queue_changed (ModestMailOperationQueue *queue,
2121 ModestMailOperation *mail_op,
2122 ModestMailOperationQueueNotification type,
2123 ModestMsgViewWindow *self)
2126 ModestMsgViewWindowPrivate *priv;
2127 ModestMailOperationTypeOperation op_type;
2128 ModestToolBarModes mode;
2130 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2131 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2133 /* If this operations was created by another window, do nothing */
2134 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2137 /* Get toolbar mode from operation id*/
2138 op_type = modest_mail_operation_get_type_operation (mail_op);
2140 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2141 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2142 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2143 mode = TOOLBAR_MODE_TRANSFER;
2146 mode = TOOLBAR_MODE_NORMAL;
2150 /* Add operation observers and change toolbar if neccessary*/
2151 tmp = priv->progress_widgets;
2153 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2154 if (mode == TOOLBAR_MODE_TRANSFER) {
2155 /* Enable transfer toolbar mode */
2156 set_toolbar_transfer_mode(self);
2158 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2160 tmp = g_slist_next (tmp);
2165 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2166 if (mode == TOOLBAR_MODE_TRANSFER) {
2168 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2170 tmp = g_slist_next (tmp);
2174 /* If no more operations are being observed, NORMAL mode is enabled again */
2175 if (observers_empty (self)) {
2176 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2184 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2186 ModestMsgViewWindowPrivate *priv;
2187 GList *selected_attachments = NULL;
2189 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2190 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2192 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2194 return selected_attachments;
2198 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2200 ModestMsgViewWindowPrivate *priv;
2201 const gchar *msg_uid;
2202 gchar *attachment_uid = NULL;
2203 gint attachment_index = 0;
2206 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2207 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2208 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2210 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2211 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2212 attachment_index = g_list_index (attachments, mime_part);
2213 g_list_free (attachments);
2215 if (msg_uid && attachment_index >= 0) {
2216 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2219 if (mime_part == NULL) {
2220 gboolean error = FALSE;
2221 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2222 if (selected_attachments == NULL) {
2224 } else if (g_list_length (selected_attachments) > 1) {
2225 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2228 mime_part = (TnyMimePart *) selected_attachments->data;
2229 g_object_ref (mime_part);
2231 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2232 g_list_free (selected_attachments);
2237 g_object_ref (mime_part);
2240 if (tny_mime_part_is_purged (mime_part)) {
2241 g_object_unref (mime_part);
2245 if (!TNY_IS_MSG (mime_part)) {
2246 gchar *filepath = NULL;
2247 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2248 TnyFsStream *temp_stream = NULL;
2249 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid,
2253 const gchar *content_type;
2254 content_type = tny_mime_part_get_content_type (mime_part);
2255 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2257 /* make the file read-only */
2258 if (g_chmod(filepath, 0444) != 0)
2259 g_warning ("%s: failed to set file '%s' to read-only: %s",
2260 __FUNCTION__, filepath, strerror(errno));
2262 modest_platform_activate_file (filepath, content_type);
2263 g_object_unref (temp_stream);
2265 /* NOTE: files in the temporary area will be automatically
2266 * cleaned after some time if they are no longer in use */
2269 /* message attachment */
2270 TnyHeader *header = NULL;
2271 ModestWindowMgr *mgr;
2272 ModestWindow *msg_win = NULL;
2275 header = tny_msg_get_header (TNY_MSG (mime_part));
2276 mgr = modest_runtime_get_window_mgr ();
2277 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2280 if (msg_win) /* there is already a window for this uid; top it */
2281 gtk_window_present (GTK_WINDOW(msg_win));
2283 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2284 * thus, we don't do anything */
2285 g_warning ("window for is already being created");
2287 /* it's not found, so create a new window for it */
2288 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2289 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2291 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2292 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2293 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2294 modest_window_get_zoom (MODEST_WINDOW (window)));
2295 modest_window_mgr_register_window (mgr, msg_win);
2296 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2297 gtk_widget_show_all (GTK_WIDGET (msg_win));
2300 g_object_unref (mime_part);
2316 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2317 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2318 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2319 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2322 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2326 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2327 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2328 g_free (pair->filename);
2329 g_object_unref (pair->part);
2330 g_slice_free (SaveMimePartPair, pair);
2332 g_list_free (info->pairs);
2335 gtk_widget_destroy (info->banner);
2336 g_object_unref (info->banner);
2337 g_slice_free (SaveMimePartInfo, info);
2342 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2344 if (info->pairs != NULL) {
2345 save_mime_part_to_file (info);
2348 result = info->result;
2350 /* This is a GDK lock because we are an idle callback and
2351 * hildon_banner_show_information is or does Gtk+ code */
2353 gdk_threads_enter (); /* CHECKED */
2354 save_mime_part_info_free (info, TRUE);
2356 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2358 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2360 gdk_threads_leave (); /* CHECKED */
2367 save_mime_part_to_file (SaveMimePartInfo *info)
2369 GnomeVFSResult result;
2370 GnomeVFSHandle *handle;
2372 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2374 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2375 if (result == GNOME_VFS_OK) {
2376 stream = tny_vfs_stream_new (handle);
2377 tny_mime_part_decode_to_stream (pair->part, stream);
2378 g_object_unref (G_OBJECT (stream));
2379 g_object_unref (pair->part);
2380 g_slice_free (SaveMimePartPair, pair);
2381 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2382 info->result = TRUE;
2384 save_mime_part_info_free (info, FALSE);
2385 info->result = FALSE;
2388 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2393 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2395 gboolean is_ok = TRUE;
2396 gint replaced_files = 0;
2397 const GList *files = info->pairs;
2400 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2401 SaveMimePartPair *pair = iter->data;
2402 if (modest_maemo_utils_file_exists (pair->filename)) {
2406 if (replaced_files) {
2407 GtkWidget *confirm_overwrite_dialog;
2408 const gchar *message = (replaced_files == 1) ?
2409 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2410 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2411 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2414 gtk_widget_destroy (confirm_overwrite_dialog);
2418 save_mime_part_info_free (info, TRUE);
2420 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2421 _CS("sfil_ib_saving"));
2422 info->banner = g_object_ref (banner);
2423 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2424 g_object_unref (banner);
2431 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2433 gboolean clean_list = FALSE;
2434 ModestMsgViewWindowPrivate *priv;
2435 GList *files_to_save = NULL;
2436 GtkWidget *save_dialog = NULL;
2437 gchar *folder = NULL;
2438 gboolean canceled = FALSE;
2439 const gchar *filename = NULL;
2440 gchar *save_multiple_str = NULL;
2442 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2443 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2445 if (mime_parts == NULL) {
2446 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2447 if (mime_parts == NULL)
2452 /* prepare dialog */
2453 if (mime_parts->next == NULL) {
2454 /* only one attachment selected */
2455 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2456 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2457 filename = tny_mime_part_get_filename (mime_part);
2459 g_warning ("Tried to save a non-file attachment");
2463 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2464 g_list_length (mime_parts));
2467 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2468 GTK_FILE_CHOOSER_ACTION_SAVE);
2471 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2472 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2476 if (filename != NULL)
2477 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2480 /* if multiple, set multiple string */
2481 if (save_multiple_str) {
2482 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2486 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2487 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2489 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2490 hildon_banner_show_information
2491 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2495 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2496 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2498 if (tny_mime_part_is_attachment (mime_part)) {
2499 SaveMimePartPair *pair;
2501 if ((mime_parts->next != NULL) &&
2502 (tny_mime_part_get_filename (mime_part) == NULL))
2505 pair = g_slice_new0 (SaveMimePartPair);
2506 if (mime_parts->next == NULL) {
2507 pair->filename = g_strdup (chooser_uri);
2510 g_build_filename (chooser_uri,
2511 tny_mime_part_get_filename (mime_part), NULL);
2513 pair->part = g_object_ref (mime_part);
2514 files_to_save = g_list_prepend (files_to_save, pair);
2518 g_free (chooser_uri);
2521 gtk_widget_destroy (save_dialog);
2524 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2525 g_list_free (mime_parts);
2528 if (files_to_save != NULL) {
2529 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2530 info->pairs = files_to_save;
2531 info->result = TRUE;
2532 save_mime_parts_to_file_with_checks (info);
2537 show_remove_attachment_information (gpointer userdata)
2539 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2540 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2542 /* We're outside the main lock */
2543 gdk_threads_enter ();
2545 if (priv->remove_attachment_banner != NULL) {
2546 gtk_widget_destroy (priv->remove_attachment_banner);
2547 g_object_unref (priv->remove_attachment_banner);
2550 priv->remove_attachment_banner = g_object_ref (
2551 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2553 gdk_threads_leave ();
2559 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2561 ModestMsgViewWindowPrivate *priv;
2562 GList *mime_parts = NULL, *node;
2563 gchar *confirmation_message;
2567 /* TnyFolder *folder; */
2569 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2570 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2573 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2575 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2577 /* Remove already purged messages from mime parts list */
2579 while (node != NULL) {
2580 TnyMimePart *part = TNY_MIME_PART (node->data);
2581 if (tny_mime_part_is_purged (part)) {
2582 GList *deleted_node = node;
2583 node = g_list_next (node);
2584 g_object_unref (part);
2585 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2587 node = g_list_next (node);
2591 if (mime_parts == NULL)
2594 n_attachments = g_list_length (mime_parts);
2595 if (n_attachments == 1) {
2596 const gchar *filename;
2598 if (TNY_IS_MSG (mime_parts->data)) {
2600 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2601 filename = tny_header_get_subject (header);
2602 g_object_unref (header);
2603 if (filename == NULL)
2604 filename = _("mail_va_no_subject");
2606 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2608 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2610 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2611 "mcen_nc_purge_files_text",
2612 n_attachments), n_attachments);
2614 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2615 confirmation_message);
2616 g_free (confirmation_message);
2618 if (response != GTK_RESPONSE_OK)
2621 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2622 /* folder = tny_msg_get_folder (msg); */
2623 /* tny_msg_uncache_attachments (msg); */
2624 /* tny_folder_refresh (folder, NULL); */
2625 /* g_object_unref (folder); */
2627 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2628 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2629 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2632 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2633 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2634 tny_msg_rewrite_cache (msg);
2635 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2637 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2638 g_list_free (mime_parts);
2640 if (priv->purge_timeout > 0) {
2641 g_source_remove (priv->purge_timeout);
2642 priv->purge_timeout = 0;
2645 if (priv->remove_attachment_banner) {
2646 gtk_widget_destroy (priv->remove_attachment_banner);
2647 g_object_unref (priv->remove_attachment_banner);
2648 priv->remove_attachment_banner = NULL;
2656 update_window_title (ModestMsgViewWindow *window)
2658 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2660 TnyHeader *header = NULL;
2661 const gchar *subject = NULL;
2663 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2666 header = tny_msg_get_header (msg);
2667 subject = tny_header_get_subject (header);
2668 g_object_unref (msg);
2671 if ((subject == NULL)||(subject[0] == '\0'))
2672 subject = _("mail_va_no_subject");
2674 gtk_window_set_title (GTK_WINDOW (window), subject);
2678 static void on_move_focus (ModestMsgViewWindow *window,
2679 GtkDirectionType direction,
2682 GtkWidget *current_focus = NULL;
2684 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2685 if ((current_focus != NULL) &&
2686 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2687 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");