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)
286 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
289 conf = modest_runtime_get_conf ();
290 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
291 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
292 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
293 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
294 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
295 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
296 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
297 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
298 modest_widget_memory_restore (conf,
300 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
304 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
306 GObjectClass *gobject_class;
307 ModestWindowClass *modest_window_class;
308 gobject_class = (GObjectClass*) klass;
309 modest_window_class = (ModestWindowClass *) klass;
311 parent_class = g_type_class_peek_parent (klass);
312 gobject_class->finalize = modest_msg_view_window_finalize;
314 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
315 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
316 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
317 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
318 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
319 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
321 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
323 modest_window_class->save_state_func = save_state;
325 signals[MSG_CHANGED_SIGNAL] =
326 g_signal_new ("msg-changed",
327 G_TYPE_FROM_CLASS (gobject_class),
329 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
331 modest_marshal_VOID__POINTER_POINTER,
332 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
335 static void modest_header_view_observer_init(
336 ModestHeaderViewObserverIface *iface_class)
338 iface_class->update_func = modest_msg_view_window_update_model_replaced;
342 modest_msg_view_window_init (ModestMsgViewWindow *obj)
344 ModestMsgViewWindowPrivate *priv;
345 ModestWindowPrivate *parent_priv = NULL;
346 GtkActionGroup *action_group = NULL;
347 GError *error = NULL;
348 GdkPixbuf *window_icon;
350 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
351 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
352 parent_priv->ui_manager = gtk_ui_manager_new();
354 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
355 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
357 /* Add common actions */
358 gtk_action_group_add_actions (action_group,
359 modest_action_entries,
360 G_N_ELEMENTS (modest_action_entries),
362 gtk_action_group_add_toggle_actions (action_group,
363 modest_toggle_action_entries,
364 G_N_ELEMENTS (modest_toggle_action_entries),
366 gtk_action_group_add_toggle_actions (action_group,
367 msg_view_toggle_action_entries,
368 G_N_ELEMENTS (msg_view_toggle_action_entries),
370 gtk_action_group_add_radio_actions (action_group,
371 msg_view_zoom_action_entries,
372 G_N_ELEMENTS (msg_view_zoom_action_entries),
374 G_CALLBACK (modest_ui_actions_on_change_zoom),
377 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
378 g_object_unref (action_group);
380 /* Load the UI definition */
381 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
384 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
385 g_error_free (error);
390 /* Add accelerators */
391 gtk_window_add_accel_group (GTK_WINDOW (obj),
392 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
394 priv->is_search_result = FALSE;
396 priv->msg_view = NULL;
397 priv->header_model = NULL;
398 priv->header_folder_id = NULL;
399 priv->clipboard_change_handler = 0;
400 priv->queue_change_handler = 0;
401 priv->account_removed_handler = 0;
402 priv->row_changed_handler = 0;
403 priv->row_deleted_handler = 0;
404 priv->row_inserted_handler = 0;
405 priv->rows_reordered_handler = 0;
406 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
408 priv->optimized_view = FALSE;
409 priv->progress_bar_timeout = 0;
410 priv->purge_timeout = 0;
411 priv->remove_attachment_banner = NULL;
412 priv->msg_uid = NULL;
415 init_window (MODEST_MSG_VIEW_WINDOW(obj));
416 /* Set window icon */
417 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
419 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
420 g_object_unref (window_icon);
424 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
425 GTK_WINDOW(obj),"applications_email_viewer");
430 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
432 ModestMsgViewWindowPrivate *priv = NULL;
434 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
436 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
438 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
440 if (priv->progress_bar_timeout > 0) {
441 g_source_remove (priv->progress_bar_timeout);
442 priv->progress_bar_timeout = 0;
449 set_toolbar_mode (ModestMsgViewWindow *self,
450 ModestToolBarModes mode)
452 ModestWindowPrivate *parent_priv;
453 ModestMsgViewWindowPrivate *priv;
454 /* GtkWidget *widget = NULL; */
456 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
458 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
459 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
461 /* Sets current toolbar mode */
462 priv->current_toolbar_mode = mode;
464 /* Update toolbar dimming state */
465 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
468 case TOOLBAR_MODE_NORMAL:
469 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
470 /* gtk_action_set_sensitive (widget, TRUE); */
471 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
472 /* gtk_action_set_sensitive (widget, TRUE); */
473 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
474 /* gtk_action_set_sensitive (widget, TRUE); */
475 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
476 /* gtk_action_set_sensitive (widget, TRUE); */
478 if (priv->prev_toolitem)
479 gtk_widget_show (priv->prev_toolitem);
481 if (priv->next_toolitem)
482 gtk_widget_show (priv->next_toolitem);
484 if (priv->progress_toolitem)
485 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
486 if (priv->progress_bar)
487 gtk_widget_hide (priv->progress_bar);
489 if (priv->cancel_toolitem)
490 gtk_widget_hide (priv->cancel_toolitem);
492 /* Hide toolbar if optimized view is enabled */
493 if (priv->optimized_view) {
494 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
495 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
499 case TOOLBAR_MODE_TRANSFER:
500 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
501 /* gtk_action_set_sensitive (widget, FALSE); */
502 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
503 /* gtk_action_set_sensitive (widget, FALSE); */
504 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
505 /* gtk_action_set_sensitive (widget, FALSE); */
506 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
507 /* gtk_action_set_sensitive (widget, FALSE); */
509 if (priv->prev_toolitem)
510 gtk_widget_hide (priv->prev_toolitem);
512 if (priv->next_toolitem)
513 gtk_widget_hide (priv->next_toolitem);
515 if (priv->progress_toolitem)
516 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
517 if (priv->progress_bar)
518 gtk_widget_show (priv->progress_bar);
520 if (priv->cancel_toolitem)
521 gtk_widget_show (priv->cancel_toolitem);
523 /* Show toolbar if it's hiden (optimized view ) */
524 if (priv->optimized_view) {
525 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
526 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
531 g_return_if_reached ();
538 menubar_to_menu (GtkUIManager *ui_manager)
540 GtkWidget *main_menu;
542 /* Get the menubar from the UI manager */
543 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
549 init_window (ModestMsgViewWindow *obj)
551 GtkWidget *main_vbox;
552 ModestMsgViewWindowPrivate *priv;
553 ModestWindowPrivate *parent_priv;
555 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
556 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
558 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
559 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
560 main_vbox = gtk_vbox_new (FALSE, 6);
562 #ifdef MODEST_USE_MOZEMBED
563 priv->main_scroll = priv->msg_view;
564 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
566 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
567 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
569 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
570 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
571 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
573 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
574 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
576 priv->find_toolbar = hildon_find_toolbar_new (NULL);
577 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
578 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
580 gtk_widget_show_all (GTK_WIDGET(main_vbox));
584 modest_msg_view_window_disconnect_signals (ModestWindow *self)
586 ModestMsgViewWindowPrivate *priv;
587 ModestHeaderView *header_view = NULL;
588 ModestWindow *main_window = NULL;
590 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
592 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
593 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
594 priv->clipboard_change_handler))
595 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
596 priv->clipboard_change_handler);
598 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
599 priv->queue_change_handler))
600 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
601 priv->queue_change_handler);
603 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
604 priv->account_removed_handler))
605 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
606 priv->account_removed_handler);
608 if (priv->header_model) {
609 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
610 priv->row_changed_handler))
611 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
612 priv->row_changed_handler);
614 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
615 priv->row_deleted_handler))
616 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
617 priv->row_deleted_handler);
619 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
620 priv->row_inserted_handler))
621 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
622 priv->row_inserted_handler);
624 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
625 priv->rows_reordered_handler))
626 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
627 priv->rows_reordered_handler);
630 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
631 FALSE); /* don't create */
635 header_view = MODEST_HEADER_VIEW(
636 modest_main_window_get_child_widget(
637 MODEST_MAIN_WINDOW(main_window),
638 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
639 if (header_view == NULL)
642 modest_header_view_remove_observer(header_view,
643 MODEST_HEADER_VIEW_OBSERVER(self));
647 modest_msg_view_window_finalize (GObject *obj)
649 ModestMsgViewWindowPrivate *priv;
651 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
653 /* Sanity check: shouldn't be needed, the window mgr should
654 call this function before */
655 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
657 if (priv->header_model != NULL) {
658 g_object_unref (priv->header_model);
659 priv->header_model = NULL;
662 if (priv->progress_bar_timeout > 0) {
663 g_source_remove (priv->progress_bar_timeout);
664 priv->progress_bar_timeout = 0;
667 if (priv->remove_attachment_banner) {
668 gtk_widget_destroy (priv->remove_attachment_banner);
669 g_object_unref (priv->remove_attachment_banner);
670 priv->remove_attachment_banner = NULL;
673 if (priv->purge_timeout > 0) {
674 g_source_remove (priv->purge_timeout);
675 priv->purge_timeout = 0;
678 if (priv->row_reference) {
679 gtk_tree_row_reference_free (priv->row_reference);
680 priv->row_reference = NULL;
683 if (priv->next_row_reference) {
684 gtk_tree_row_reference_free (priv->next_row_reference);
685 priv->next_row_reference = NULL;
689 g_free (priv->msg_uid);
690 priv->msg_uid = NULL;
693 G_OBJECT_CLASS(parent_class)->finalize (obj);
697 select_next_valid_row (GtkTreeModel *model,
698 GtkTreeRowReference **row_reference,
701 GtkTreeIter tmp_iter;
702 GtkTreePath *path, *next;
703 gboolean retval = FALSE;
705 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
707 path = gtk_tree_row_reference_get_path (*row_reference);
708 gtk_tree_model_get_iter (model, &tmp_iter, path);
709 gtk_tree_row_reference_free (*row_reference);
710 *row_reference = NULL;
712 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
713 next = gtk_tree_model_get_path (model, &tmp_iter);
714 *row_reference = gtk_tree_row_reference_new (model, next);
716 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
717 next = gtk_tree_model_get_path (model, &tmp_iter);
719 /* Ensure that we are not selecting the same */
720 if (gtk_tree_path_compare (path, next) != 0) {
721 *row_reference = gtk_tree_row_reference_new (model, next);
727 gtk_tree_path_free (path);
732 /* TODO: This should be in _init(), with the parameters as properties. */
734 modest_msg_view_window_construct (ModestMsgViewWindow *self,
735 const gchar *modest_account_name,
736 const gchar *msg_uid)
739 ModestMsgViewWindowPrivate *priv = NULL;
740 ModestWindowPrivate *parent_priv = NULL;
741 ModestDimmingRulesGroup *menu_rules_group = NULL;
742 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
743 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
745 obj = G_OBJECT (self);
746 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
747 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
749 priv->msg_uid = g_strdup (msg_uid);
752 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
753 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
754 gtk_widget_show (parent_priv->menubar);
755 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
757 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
758 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
759 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
761 /* Add common dimming rules */
762 modest_dimming_rules_group_add_rules (menu_rules_group,
763 modest_msg_view_menu_dimming_entries,
764 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
765 MODEST_WINDOW (self));
766 modest_dimming_rules_group_add_rules (toolbar_rules_group,
767 modest_msg_view_toolbar_dimming_entries,
768 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
769 MODEST_WINDOW (self));
770 modest_dimming_rules_group_add_rules (clipboard_rules_group,
771 modest_msg_view_clipboard_dimming_entries,
772 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
773 MODEST_WINDOW (self));
775 /* Insert dimming rules group for this window */
776 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
777 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
778 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
779 g_object_unref (menu_rules_group);
780 g_object_unref (toolbar_rules_group);
781 g_object_unref (clipboard_rules_group);
783 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
785 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
787 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);
788 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
789 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
790 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
791 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
792 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
793 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
794 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
795 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
796 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
797 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
799 g_signal_connect (G_OBJECT (obj), "key-release-event",
800 G_CALLBACK (modest_msg_view_window_key_release_event),
803 g_signal_connect (G_OBJECT (obj), "window-state-event",
804 G_CALLBACK (modest_msg_view_window_window_state_event),
807 g_signal_connect (G_OBJECT (obj), "move-focus",
808 G_CALLBACK (on_move_focus), obj);
810 /* Mail Operation Queue */
811 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
813 G_CALLBACK (on_queue_changed),
816 /* Account manager */
817 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
819 G_CALLBACK(on_account_removed),
822 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
824 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
825 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
826 priv->last_search = NULL;
828 /* Init the clipboard actions dim status */
829 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
831 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
833 /* Check toolbar dimming rules */
834 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
835 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
839 /* FIXME: parameter checks */
841 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
842 const gchar *modest_account_name,
843 const gchar *msg_uid,
845 GtkTreeRowReference *row_reference)
847 ModestMsgViewWindow *window = NULL;
848 ModestMsgViewWindowPrivate *priv = NULL;
849 TnyFolder *header_folder = NULL;
850 ModestHeaderView *header_view = NULL;
851 ModestWindow *main_window = NULL;
852 ModestWindowMgr *mgr = NULL;
854 mgr = modest_runtime_get_window_mgr ();
855 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
856 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
858 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
860 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
862 /* Remember the message list's TreeModel so we can detect changes
863 * and change the list selection when necessary: */
865 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
867 g_warning ("%s: BUG: no main window", __FUNCTION__);
871 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
872 MODEST_MAIN_WINDOW(main_window),
873 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
874 if (header_view != NULL){
875 header_folder = modest_header_view_get_folder(header_view);
876 g_assert(header_folder != NULL);
877 priv->header_folder_id = tny_folder_get_id(header_folder);
878 g_assert(priv->header_folder_id != NULL);
879 g_object_unref(header_folder);
882 priv->header_model = g_object_ref(model);
883 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
884 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
885 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
887 priv->row_changed_handler = g_signal_connect(
888 GTK_TREE_MODEL(model), "row-changed",
889 G_CALLBACK(modest_msg_view_window_on_row_changed),
891 priv->row_deleted_handler = g_signal_connect(
892 GTK_TREE_MODEL(model), "row-deleted",
893 G_CALLBACK(modest_msg_view_window_on_row_deleted),
895 priv->row_inserted_handler = g_signal_connect (
896 GTK_TREE_MODEL(model), "row-inserted",
897 G_CALLBACK(modest_msg_view_window_on_row_inserted),
899 priv->rows_reordered_handler = g_signal_connect(
900 GTK_TREE_MODEL(model), "rows-reordered",
901 G_CALLBACK(modest_msg_view_window_on_row_reordered),
904 if (header_view != NULL){
905 modest_header_view_add_observer(header_view,
906 MODEST_HEADER_VIEW_OBSERVER(window));
909 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
910 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
911 gtk_widget_show_all (GTK_WIDGET (window));
913 modest_msg_view_window_update_priority (window);
915 /* Check toolbar dimming rules */
916 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
918 return MODEST_WINDOW(window);
922 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
923 const gchar *modest_account_name,
924 const gchar *msg_uid)
926 ModestMsgViewWindow *window = NULL;
927 ModestMsgViewWindowPrivate *priv = NULL;
928 ModestWindowMgr *mgr = NULL;
930 mgr = modest_runtime_get_window_mgr ();
931 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
932 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
933 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
935 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
937 /* Remember that this is a search result,
938 * so we can disable some UI appropriately: */
939 priv->is_search_result = TRUE;
941 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
942 update_window_title (window);
944 return MODEST_WINDOW(window);
948 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
949 const gchar *modest_account_name,
950 const gchar *msg_uid)
953 ModestMsgViewWindowPrivate *priv;
954 ModestWindowMgr *mgr = NULL;
956 g_return_val_if_fail (msg, NULL);
957 mgr = modest_runtime_get_window_mgr ();
958 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
959 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
960 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
961 modest_account_name, msg_uid);
963 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
964 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
966 return MODEST_WINDOW(obj);
969 void modest_msg_view_window_on_row_changed(
970 GtkTreeModel *header_model,
973 ModestMsgViewWindow *window){
974 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
977 void modest_msg_view_window_on_row_deleted(
978 GtkTreeModel *header_model,
980 ModestMsgViewWindow *window){
981 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
984 /* On insertions we check if the folder still has the message we are
985 * showing or do not. If do not, we do nothing. Which means we are still
986 * not attached to any header folder and thus next/prev buttons are
987 * still dimmed. Once the message that is shown by msg-view is found, the
988 * new model of header-view will be attached and the references will be set.
989 * On each further insertions dimming rules will be checked. However
990 * this requires extra CPU time at least works.
991 * (An message might be deleted from TnyFolder and thus will not be
992 * inserted into the model again for example if it is removed by the
993 * imap server and the header view is refreshed.)
995 void modest_msg_view_window_on_row_inserted(
996 GtkTreeModel *new_model,
997 GtkTreePath *tree_path,
998 GtkTreeIter *tree_iter,
999 ModestMsgViewWindow *window){
1000 ModestMsgViewWindowPrivate *priv = NULL;
1001 TnyHeader *header = NULL;
1004 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1006 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1008 /* If we already has a model attached then the message shown by
1009 * msg-view is in it, and thus we do not need any actions but
1010 * to check the dimming rules.*/
1011 if(priv->header_model != NULL){
1012 gtk_tree_row_reference_free(priv->next_row_reference);
1013 priv->next_row_reference = gtk_tree_row_reference_copy(
1014 priv->row_reference);
1015 select_next_valid_row (priv->header_model,
1016 &(priv->next_row_reference), FALSE);
1017 modest_ui_actions_check_toolbar_dimming_rules (
1018 MODEST_WINDOW (window));
1022 /* Check if the newly inserted message is the same we are actually
1023 * showing. IF not, we should remain detached from the header model
1024 * and thus prev and next toolbarbuttons should remain dimmed. */
1025 gtk_tree_model_get (new_model, tree_iter,
1026 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1027 uid = modest_tny_folder_get_header_unique_id(header);
1028 g_object_unref(G_OBJECT(header));
1030 if(!g_str_equal(priv->msg_uid, uid)){
1036 /* Setup row_reference for the actual msg. */
1037 priv->row_reference = gtk_tree_row_reference_new(
1038 new_model, tree_path);
1039 if(priv->row_reference == NULL){
1040 g_warning("No reference for msg header item.");
1044 /* Attach new_model and connect some callback to it to become able
1045 * to detect changes in header-view. */
1046 priv->header_model = g_object_ref(new_model);
1047 g_signal_connect (new_model, "row-changed",
1048 G_CALLBACK (modest_msg_view_window_on_row_changed),
1050 g_signal_connect (new_model, "row-deleted",
1051 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1053 g_signal_connect (new_model, "rows-reordered",
1054 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1057 /* Now set up next_row_reference. */
1058 priv->next_row_reference = gtk_tree_row_reference_copy(
1059 priv->row_reference);
1060 select_next_valid_row (priv->header_model,
1061 &(priv->next_row_reference), FALSE);
1063 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1066 void modest_msg_view_window_on_row_reordered(
1067 GtkTreeModel *header_model,
1071 ModestMsgViewWindow *window){
1072 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1075 /* The modest_msg_view_window_update_model_replaced implements update
1076 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1077 * actually belongs to the header-view is the same as the TnyFolder of
1078 * the message of msg-view or not. If they are different, there is
1079 * nothing to do. If they are the same, then the model has replaced and
1080 * the reference in msg-view shall be replaced from the old model to
1081 * the new model. In this case the view will be detached from it's
1082 * header folder. From this point the next/prev buttons are dimmed.
1084 void modest_msg_view_window_update_model_replaced(
1085 ModestHeaderViewObserver *observer,
1086 GtkTreeModel *model,
1087 const gchar *tny_folder_id){
1088 ModestMsgViewWindowPrivate *priv = NULL;
1089 ModestMsgViewWindow *window = NULL;
1091 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1092 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1094 window = MODEST_MSG_VIEW_WINDOW(observer);
1095 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1097 /* If there is an other folder in the header-view then we do
1098 * not care about it's model (msg list). Else if the
1099 * header-view shows the folder the msg shown by us is in, we
1100 * shall replace our model reference and make some check. */
1101 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1104 /* Model is changed(replaced), so we should forget the old
1105 * one. Because there might be other references and there
1106 * might be some change on the model even if we unreferenced
1107 * it, we need to disconnect our signals here. */
1108 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1109 priv->row_changed_handler))
1110 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1111 priv->row_changed_handler);
1112 priv->row_changed_handler = 0;
1113 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1114 priv->row_deleted_handler))
1115 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1116 priv->row_deleted_handler);
1117 priv->row_deleted_handler = 0;
1118 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1119 priv->row_inserted_handler))
1120 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1121 priv->row_inserted_handler);
1122 priv->row_inserted_handler = 0;
1123 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1124 priv->rows_reordered_handler))
1125 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1126 priv->rows_reordered_handler);
1127 priv->rows_reordered_handler = 0;
1128 g_object_unref(priv->header_model);
1129 priv->header_model = NULL;
1130 g_object_unref(priv->row_reference);
1131 priv->row_reference = NULL;
1132 g_object_unref(priv->next_row_reference);
1133 priv->next_row_reference = NULL;
1135 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1137 g_assert(model != NULL);
1139 /* Also we must connect to the new model for row insertions.
1140 * Only for insertions now. We will need other ones only after
1141 * the msg is show by msg-view is added to the new model. */
1142 priv->row_inserted_handler = g_signal_connect (
1143 model, "row-inserted",
1144 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1149 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1151 ModestMsgViewWindowPrivate *priv= NULL;
1153 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1154 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1156 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1160 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1162 ModestMsgViewWindowPrivate *priv= NULL;
1164 TnyHeader *header = NULL;
1165 GtkTreePath *path = NULL;
1168 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1169 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1171 /* If the message was not obtained from a treemodel,
1172 * for instance if it was opened directly by the search UI:
1174 if (priv->header_model == NULL) {
1175 msg = modest_msg_view_window_get_message (self);
1177 header = tny_msg_get_header (msg);
1178 g_object_unref (msg);
1183 /* Get iter of the currently selected message in the header view: */
1184 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1185 * instead of sometimes retrieving it from the header view?
1186 * Then we wouldn't be dependent on the message actually still being selected
1187 * in the header view. murrayc. */
1188 if (!gtk_tree_row_reference_valid (priv->row_reference))
1190 path = gtk_tree_row_reference_get_path (priv->row_reference);
1191 g_return_val_if_fail (path != NULL, NULL);
1192 gtk_tree_model_get_iter (priv->header_model,
1196 /* Get current message header */
1197 gtk_tree_model_get (priv->header_model, &iter,
1198 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1201 gtk_tree_path_free (path);
1206 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1208 ModestMsgViewWindowPrivate *priv;
1210 g_return_val_if_fail (self, NULL);
1212 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1214 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1218 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1220 ModestMsgViewWindowPrivate *priv;
1222 g_return_val_if_fail (self, NULL);
1224 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1226 return (const gchar*) priv->msg_uid;
1230 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1233 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1234 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1235 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1239 is_active = gtk_toggle_action_get_active (toggle);
1242 gtk_widget_show (priv->find_toolbar);
1243 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1245 gtk_widget_hide (priv->find_toolbar);
1248 /* update the toggle buttons status */
1249 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1250 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1251 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1252 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1257 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1258 ModestMsgViewWindow *obj)
1260 GtkToggleAction *toggle;
1261 ModestWindowPrivate *parent_priv;
1262 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1264 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1265 gtk_toggle_action_set_active (toggle, FALSE);
1269 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1270 ModestMsgViewWindow *obj)
1272 gchar *current_search;
1273 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1275 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1276 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1280 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1282 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1283 g_free (current_search);
1284 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1288 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1290 g_free (priv->last_search);
1291 priv->last_search = g_strdup (current_search);
1292 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1295 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1296 g_free (priv->last_search);
1297 priv->last_search = NULL;
1299 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1302 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1303 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1304 g_free (priv->last_search);
1305 priv->last_search = NULL;
1307 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1311 g_free (current_search);
1316 modest_msg_view_window_set_zoom (ModestWindow *window,
1319 ModestMsgViewWindowPrivate *priv;
1320 ModestWindowPrivate *parent_priv;
1321 GtkAction *action = NULL;
1322 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1324 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1326 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1327 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1328 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1330 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1331 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1333 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1337 modest_msg_view_window_get_zoom (ModestWindow *window)
1339 ModestMsgViewWindowPrivate *priv;
1341 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1343 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1344 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1348 modest_msg_view_window_zoom_plus (ModestWindow *window)
1350 ModestWindowPrivate *parent_priv;
1351 GtkRadioAction *zoom_radio_action;
1352 GSList *group, *node;
1354 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1355 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1356 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1358 group = gtk_radio_action_get_group (zoom_radio_action);
1360 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1361 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1365 for (node = group; node != NULL; node = g_slist_next (node)) {
1366 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1367 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1375 modest_msg_view_window_zoom_minus (ModestWindow *window)
1377 ModestWindowPrivate *parent_priv;
1378 GtkRadioAction *zoom_radio_action;
1379 GSList *group, *node;
1381 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1382 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1383 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1385 group = gtk_radio_action_get_group (zoom_radio_action);
1387 for (node = group; node != NULL; node = g_slist_next (node)) {
1388 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1389 if (node->next != NULL) {
1390 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1393 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1403 modest_msg_view_window_key_release_event (GtkWidget *window,
1407 if (event->type == GDK_KEY_RELEASE) {
1408 switch (event->keyval) {
1410 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1414 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1427 modest_msg_view_window_scroll_up (ModestWindow *window)
1429 ModestMsgViewWindowPrivate *priv;
1430 gboolean return_value;
1432 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1433 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1437 modest_msg_view_window_scroll_down (ModestWindow *window)
1439 ModestMsgViewWindowPrivate *priv;
1440 gboolean return_value;
1442 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1443 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1447 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1450 ModestMsgViewWindowPrivate *priv;
1451 GtkTreeIter tmp_iter;
1452 gboolean is_last_selected;
1454 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1455 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1457 /*if no model (so no rows at all), then virtually we are the last*/
1458 if (!priv->header_model)
1461 path = gtk_tree_row_reference_get_path (priv->row_reference);
1465 is_last_selected = TRUE;
1466 while (is_last_selected) {
1468 gtk_tree_path_next (path);
1469 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1471 gtk_tree_model_get (priv->header_model, &tmp_iter,
1472 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1475 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1476 is_last_selected = FALSE;
1477 g_object_unref(G_OBJECT(header));
1480 gtk_tree_path_free (path);
1481 return is_last_selected;
1485 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1487 ModestMsgViewWindowPrivate *priv;
1489 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1490 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1492 return priv->header_model != NULL;
1496 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1498 ModestMsgViewWindowPrivate *priv;
1500 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1501 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1503 return priv->is_search_result;
1507 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1510 ModestMsgViewWindowPrivate *priv;
1511 gboolean is_first_selected;
1512 GtkTreeIter tmp_iter;
1513 /* gchar * path_string;*/
1515 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1516 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1518 /*if no model (so no rows at all), then virtually we are the first*/
1519 if (!priv->header_model)
1522 path = gtk_tree_row_reference_get_path (priv->row_reference);
1526 /* path_string = gtk_tree_path_to_string (path);
1527 is_first_selected = strcmp (path_string, "0");
1529 g_free (path_string);
1530 gtk_tree_path_free (path);
1532 return is_first_selected;*/
1534 is_first_selected = TRUE;
1535 while (is_first_selected) {
1537 if(!gtk_tree_path_prev (path))
1539 /* Here the 'if' is needless for logic, but let make sure
1540 * iter is valid for gtk_tree_model_get. */
1541 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1543 gtk_tree_model_get (priv->header_model, &tmp_iter,
1544 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1547 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1548 is_first_selected = FALSE;
1549 g_object_unref(G_OBJECT(header));
1552 gtk_tree_path_free (path);
1553 return is_first_selected;
1557 * Reads the message whose summary item is @header. It takes care of
1558 * several things, among others:
1560 * If the message was not previously downloaded then ask the user
1561 * before downloading. If there is no connection launch the connection
1562 * dialog. Update toolbar dimming rules.
1564 * Returns: TRUE if the mail operation was started, otherwise if the
1565 * user do not want to download the message, or if the user do not
1566 * want to connect, then the operation is not issued
1569 message_reader (ModestMsgViewWindow *window,
1570 ModestMsgViewWindowPrivate *priv,
1572 GtkTreeRowReference *row_reference)
1574 ModestMailOperation *mail_op = NULL;
1575 ModestMailOperationTypeOperation op_type;
1576 gboolean already_showing = FALSE;
1577 ModestWindow *msg_window = NULL;
1578 ModestWindowMgr *mgr;
1580 g_return_val_if_fail (row_reference != NULL, FALSE);
1582 mgr = modest_runtime_get_window_mgr ();
1583 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1584 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1587 gtk_window_present (GTK_WINDOW (msg_window));
1588 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1592 /* Msg download completed */
1593 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1594 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1596 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1598 /* Ask the user if he wants to download the message if
1600 if (!tny_device_is_online (modest_runtime_get_device())) {
1601 TnyFolder *folder = NULL;
1602 GtkResponseType response;
1604 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1605 _("mcen_nc_get_msg"));
1606 if (response == GTK_RESPONSE_CANCEL)
1609 /* Offer the connection dialog if necessary */
1610 folder = tny_header_get_folder (header);
1612 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1613 TNY_FOLDER_STORE (folder))) {
1614 g_object_unref (folder);
1617 g_object_unref (folder);
1622 /* New mail operation */
1623 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1624 modest_ui_actions_get_msgs_full_error_handler,
1627 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1628 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1629 g_object_unref (mail_op);
1631 /* Update toolbar dimming rules */
1632 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1638 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1640 ModestMsgViewWindowPrivate *priv;
1641 GtkTreePath *path= NULL;
1642 GtkTreeIter tmp_iter;
1644 gboolean retval = TRUE;
1645 GtkTreeRowReference *row_reference = NULL;
1647 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1648 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1650 /* Update the next row reference if it's not valid. This could
1651 happen if for example the header which it was pointing to,
1652 was deleted. The best place to do it is in the row-deleted
1653 handler but the tinymail model do not work like the glib
1654 tree models and reports the deletion when the row is still
1656 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1657 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1658 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1659 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1662 if (priv->next_row_reference)
1663 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1667 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1669 gtk_tree_model_get_iter (priv->header_model,
1672 gtk_tree_path_free (path);
1674 gtk_tree_model_get (priv->header_model, &tmp_iter,
1675 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1678 /* Read the message & show it */
1679 if (!message_reader (window, priv, header, row_reference)) {
1681 gtk_tree_row_reference_free (row_reference);
1685 g_object_unref (header);
1691 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1693 ModestMsgViewWindowPrivate *priv = NULL;
1694 TnyHeader *header = NULL;
1696 GtkTreePath *path = NULL;
1697 GtkTreeRowReference *row_reference = NULL;
1699 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1700 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1702 /* Check that the model is not empty */
1703 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1706 /* Get the header */
1707 gtk_tree_model_get (priv->header_model,
1709 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1711 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1712 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1713 g_object_unref (header);
1714 return modest_msg_view_window_select_next_message (self);
1717 path = gtk_tree_model_get_path (priv->header_model, &iter);
1718 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1719 gtk_tree_path_free (path);
1721 /* Read the message & show it */
1722 message_reader (self, priv, header, row_reference);
1725 g_object_unref (header);
1731 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1733 ModestMsgViewWindowPrivate *priv = NULL;
1735 GtkTreeRowReference *row_reference = NULL;
1737 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1738 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1740 /* Return inmediatly if there is no header model */
1741 if (!priv->header_model)
1744 path = gtk_tree_row_reference_get_path (priv->row_reference);
1745 while (gtk_tree_path_prev (path)) {
1749 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1750 gtk_tree_model_get (priv->header_model, &iter,
1751 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1755 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1756 g_object_unref (header);
1760 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1761 /* Read the message & show it */
1762 if (!message_reader (window, priv, header, row_reference)) {
1763 gtk_tree_row_reference_free (row_reference);
1764 g_object_unref (header);
1768 gtk_tree_path_free (path);
1769 g_object_unref (header);
1774 gtk_tree_path_free (path);
1779 view_msg_cb (ModestMailOperation *mail_op,
1786 ModestMsgViewWindow *self = NULL;
1787 ModestMsgViewWindowPrivate *priv = NULL;
1788 GtkTreeRowReference *row_reference = NULL;
1790 /* If there was any error */
1791 row_reference = (GtkTreeRowReference *) user_data;
1792 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1793 gtk_tree_row_reference_free (row_reference);
1797 /* Get the window */
1798 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1799 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1800 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1802 /* Update the row reference */
1803 gtk_tree_row_reference_free (priv->row_reference);
1804 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1805 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1806 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1807 gtk_tree_row_reference_free (row_reference);
1809 /* Mark header as read */
1810 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1811 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1813 /* Set new message */
1814 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1815 modest_msg_view_window_update_priority (self);
1816 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1817 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1819 /* Set the new message uid of the window */
1820 if (priv->msg_uid) {
1821 g_free (priv->msg_uid);
1822 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1825 /* Notify the observers */
1826 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1827 0, priv->header_model, priv->row_reference);
1829 /* Free new references */
1830 g_object_unref (self);
1834 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1836 ModestMsgViewWindowPrivate *priv;
1838 TnyFolderType folder_type;
1840 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1842 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1844 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1848 folder = tny_msg_get_folder (msg);
1850 folder_type = tny_folder_get_folder_type (folder);
1851 g_object_unref (folder);
1853 g_object_unref (msg);
1861 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1863 ModestMsgViewWindowPrivate *priv;
1864 TnyHeaderFlags flags = 0;
1866 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1868 if (priv->header_model) {
1871 GtkTreePath *path = NULL;
1873 path = gtk_tree_row_reference_get_path (priv->row_reference);
1874 g_return_if_fail (path != NULL);
1875 gtk_tree_model_get_iter (priv->header_model,
1877 gtk_tree_row_reference_get_path (priv->row_reference));
1879 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1882 flags = tny_header_get_flags (header);
1883 g_object_unref(G_OBJECT(header));
1885 gtk_tree_path_free (path);
1888 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1893 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1895 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1896 ModestWindowPrivate *parent_priv;
1897 ModestWindowMgr *mgr;
1898 gboolean is_fullscreen;
1899 GtkAction *fs_toggle_action;
1902 mgr = modest_runtime_get_window_mgr ();
1903 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1905 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1907 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1908 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1909 if (is_fullscreen != active) {
1910 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1919 set_homogeneous (GtkWidget *widget,
1922 if (GTK_IS_TOOL_ITEM (widget)) {
1923 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1924 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1929 modest_msg_view_window_show_toolbar (ModestWindow *self,
1930 gboolean show_toolbar)
1932 ModestMsgViewWindowPrivate *priv = NULL;
1933 ModestWindowPrivate *parent_priv;
1934 GtkWidget *reply_button = NULL, *menu = NULL;
1935 GtkWidget *placeholder = NULL;
1937 const gchar *action_name;
1940 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1941 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1943 /* Set optimized view status */
1944 priv->optimized_view = !show_toolbar;
1946 if (!parent_priv->toolbar) {
1947 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1949 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1951 /* Set homogeneous toolbar */
1952 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1953 set_homogeneous, NULL);
1955 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1956 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1957 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1958 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1959 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1960 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1961 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1962 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1964 /* Add ProgressBar (Transfer toolbar) */
1965 priv->progress_bar = modest_progress_bar_widget_new ();
1966 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1967 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1968 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1969 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1970 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1972 /* Connect cancel 'clicked' signal to abort progress mode */
1973 g_signal_connect(priv->cancel_toolitem, "clicked",
1974 G_CALLBACK(cancel_progressbar),
1977 /* Add it to the observers list */
1978 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1981 hildon_window_add_toolbar (HILDON_WINDOW (self),
1982 GTK_TOOLBAR (parent_priv->toolbar));
1985 /* Set reply button tap and hold menu */
1986 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1987 "/ToolBar/ToolbarMessageReply");
1988 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1989 "/ToolbarReplyCSM");
1990 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1994 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1995 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1996 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1998 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1999 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2000 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2002 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2005 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2006 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2009 /* Update also the actions (to update the toggles in the
2010 menus), we have to do it manually because some other window
2011 of the same time could have changed it (remember that the
2012 toolbar fullscreen mode is shared by all the windows of the
2014 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2015 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2017 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2019 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2020 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2025 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2027 ModestMsgViewWindow *window)
2029 if (!GTK_WIDGET_VISIBLE (window))
2032 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2036 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2038 ModestMsgViewWindowPrivate *priv;
2040 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2041 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2043 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2047 cancel_progressbar (GtkToolButton *toolbutton,
2048 ModestMsgViewWindow *self)
2051 ModestMsgViewWindowPrivate *priv;
2053 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2055 /* Get operation observers and cancel its current operation */
2056 tmp = priv->progress_widgets;
2058 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2059 tmp=g_slist_next(tmp);
2063 observers_empty (ModestMsgViewWindow *self)
2066 ModestMsgViewWindowPrivate *priv;
2067 gboolean is_empty = TRUE;
2068 guint pending_ops = 0;
2070 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2071 tmp = priv->progress_widgets;
2073 /* Check all observers */
2074 while (tmp && is_empty) {
2075 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2076 is_empty = pending_ops == 0;
2078 tmp = g_slist_next(tmp);
2085 on_account_removed (TnyAccountStore *account_store,
2086 TnyAccount *account,
2089 /* Do nothing if it's a transport account, because we only
2090 show the messages of a store account */
2091 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2092 const gchar *parent_acc = NULL;
2093 const gchar *our_acc = NULL;
2095 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2096 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2098 /* Close this window if I'm showing a message of the removed account */
2099 if (strcmp (parent_acc, our_acc) == 0)
2100 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2105 on_queue_changed (ModestMailOperationQueue *queue,
2106 ModestMailOperation *mail_op,
2107 ModestMailOperationQueueNotification type,
2108 ModestMsgViewWindow *self)
2111 ModestMsgViewWindowPrivate *priv;
2112 ModestMailOperationTypeOperation op_type;
2113 ModestToolBarModes mode;
2115 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2116 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2118 /* If this operations was created by another window, do nothing */
2119 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2122 /* Get toolbar mode from operation id*/
2123 op_type = modest_mail_operation_get_type_operation (mail_op);
2125 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2126 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2127 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2128 mode = TOOLBAR_MODE_TRANSFER;
2131 mode = TOOLBAR_MODE_NORMAL;
2135 /* Add operation observers and change toolbar if neccessary*/
2136 tmp = priv->progress_widgets;
2138 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2139 if (mode == TOOLBAR_MODE_TRANSFER) {
2140 /* Enable transfer toolbar mode */
2141 set_toolbar_transfer_mode(self);
2143 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2145 tmp = g_slist_next (tmp);
2150 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2151 if (mode == TOOLBAR_MODE_TRANSFER) {
2153 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2155 tmp = g_slist_next (tmp);
2159 /* If no more operations are being observed, NORMAL mode is enabled again */
2160 if (observers_empty (self)) {
2161 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2169 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2171 ModestMsgViewWindowPrivate *priv;
2172 GList *selected_attachments = NULL;
2174 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2175 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2177 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2179 return selected_attachments;
2183 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2185 ModestMsgViewWindowPrivate *priv;
2186 const gchar *msg_uid;
2187 gchar *attachment_uid = NULL;
2188 gint attachment_index = 0;
2191 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2192 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2193 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2195 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2196 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2197 attachment_index = g_list_index (attachments, mime_part);
2198 g_list_free (attachments);
2200 if (msg_uid && attachment_index >= 0) {
2201 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2204 if (mime_part == NULL) {
2205 gboolean error = FALSE;
2206 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2207 if (selected_attachments == NULL) {
2209 } else if (g_list_length (selected_attachments) > 1) {
2210 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2213 mime_part = (TnyMimePart *) selected_attachments->data;
2214 g_object_ref (mime_part);
2216 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2217 g_list_free (selected_attachments);
2222 g_object_ref (mime_part);
2225 if (tny_mime_part_is_purged (mime_part)) {
2226 g_object_unref (mime_part);
2230 if (!TNY_IS_MSG (mime_part)) {
2231 gchar *filepath = NULL;
2232 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2233 TnyFsStream *temp_stream = NULL;
2234 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid,
2238 const gchar *content_type;
2239 content_type = tny_mime_part_get_content_type (mime_part);
2240 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2242 /* make the file read-only */
2243 if (g_chmod(filepath, 0444) != 0)
2244 g_warning ("%s: failed to set file '%s' to read-only: %s",
2245 __FUNCTION__, filepath, strerror(errno));
2247 modest_platform_activate_file (filepath, content_type);
2248 g_object_unref (temp_stream);
2250 /* NOTE: files in the temporary area will be automatically
2251 * cleaned after some time if they are no longer in use */
2254 /* message attachment */
2255 TnyHeader *header = NULL;
2256 ModestWindowMgr *mgr;
2257 ModestWindow *msg_win = NULL;
2260 header = tny_msg_get_header (TNY_MSG (mime_part));
2261 mgr = modest_runtime_get_window_mgr ();
2262 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2265 if (msg_win) /* there is already a window for this uid; top it */
2266 gtk_window_present (GTK_WINDOW(msg_win));
2268 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2269 * thus, we don't do anything */
2270 g_warning ("window for is already being created");
2272 /* it's not found, so create a new window for it */
2273 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2274 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2276 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2277 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2278 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2279 modest_window_get_zoom (MODEST_WINDOW (window)));
2280 modest_window_mgr_register_window (mgr, msg_win);
2281 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2282 gtk_widget_show_all (GTK_WIDGET (msg_win));
2285 g_object_unref (mime_part);
2301 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2302 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2303 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2304 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2307 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2311 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2312 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2313 g_free (pair->filename);
2314 g_object_unref (pair->part);
2315 g_slice_free (SaveMimePartPair, pair);
2317 g_list_free (info->pairs);
2320 gtk_widget_destroy (info->banner);
2321 g_object_unref (info->banner);
2322 g_slice_free (SaveMimePartInfo, info);
2327 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2329 if (info->pairs != NULL) {
2330 save_mime_part_to_file (info);
2333 result = info->result;
2335 /* This is a GDK lock because we are an idle callback and
2336 * hildon_banner_show_information is or does Gtk+ code */
2338 gdk_threads_enter (); /* CHECKED */
2339 save_mime_part_info_free (info, TRUE);
2341 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2343 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2345 gdk_threads_leave (); /* CHECKED */
2352 save_mime_part_to_file (SaveMimePartInfo *info)
2354 GnomeVFSResult result;
2355 GnomeVFSHandle *handle;
2357 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2359 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2360 if (result == GNOME_VFS_OK) {
2361 stream = tny_vfs_stream_new (handle);
2362 tny_mime_part_decode_to_stream (pair->part, stream);
2363 g_object_unref (G_OBJECT (stream));
2364 g_object_unref (pair->part);
2365 g_slice_free (SaveMimePartPair, pair);
2366 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2367 info->result = TRUE;
2369 save_mime_part_info_free (info, FALSE);
2370 info->result = FALSE;
2373 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2378 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2380 gboolean is_ok = TRUE;
2381 gint replaced_files = 0;
2382 const GList *files = info->pairs;
2385 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2386 SaveMimePartPair *pair = iter->data;
2387 if (modest_maemo_utils_file_exists (pair->filename)) {
2391 if (replaced_files) {
2392 GtkWidget *confirm_overwrite_dialog;
2393 const gchar *message = (replaced_files == 1) ?
2394 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2395 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2396 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2399 gtk_widget_destroy (confirm_overwrite_dialog);
2403 save_mime_part_info_free (info, TRUE);
2405 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2406 _CS("sfil_ib_saving"));
2407 info->banner = g_object_ref (banner);
2408 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2409 g_object_unref (banner);
2416 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2418 gboolean clean_list = FALSE;
2419 ModestMsgViewWindowPrivate *priv;
2420 GList *files_to_save = NULL;
2421 GtkWidget *save_dialog = NULL;
2422 gchar *folder = NULL;
2423 gboolean canceled = FALSE;
2424 const gchar *filename = NULL;
2425 gchar *save_multiple_str = NULL;
2427 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2428 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2430 if (mime_parts == NULL) {
2431 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2432 if (mime_parts == NULL)
2437 /* prepare dialog */
2438 if (mime_parts->next == NULL) {
2439 /* only one attachment selected */
2440 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2441 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2442 filename = tny_mime_part_get_filename (mime_part);
2444 g_warning ("Tried to save a non-file attachment");
2448 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2449 g_list_length (mime_parts));
2452 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2453 GTK_FILE_CHOOSER_ACTION_SAVE);
2456 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2457 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2461 if (filename != NULL)
2462 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2465 /* if multiple, set multiple string */
2466 if (save_multiple_str) {
2467 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2471 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2472 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2474 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2475 hildon_banner_show_information
2476 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2480 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2481 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2483 if (tny_mime_part_is_attachment (mime_part)) {
2484 SaveMimePartPair *pair;
2486 if ((mime_parts->next != NULL) &&
2487 (tny_mime_part_get_filename (mime_part) == NULL))
2490 pair = g_slice_new0 (SaveMimePartPair);
2491 if (mime_parts->next == NULL) {
2492 pair->filename = g_strdup (chooser_uri);
2495 g_build_filename (chooser_uri,
2496 tny_mime_part_get_filename (mime_part), NULL);
2498 pair->part = g_object_ref (mime_part);
2499 files_to_save = g_list_prepend (files_to_save, pair);
2503 g_free (chooser_uri);
2506 gtk_widget_destroy (save_dialog);
2509 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2510 g_list_free (mime_parts);
2513 if (files_to_save != NULL) {
2514 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2515 info->pairs = files_to_save;
2516 info->result = TRUE;
2517 save_mime_parts_to_file_with_checks (info);
2522 show_remove_attachment_information (gpointer userdata)
2524 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2525 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2527 /* We're outside the main lock */
2528 gdk_threads_enter ();
2530 if (priv->remove_attachment_banner != NULL) {
2531 gtk_widget_destroy (priv->remove_attachment_banner);
2532 g_object_unref (priv->remove_attachment_banner);
2535 priv->remove_attachment_banner = g_object_ref (
2536 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2538 gdk_threads_leave ();
2544 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2546 ModestMsgViewWindowPrivate *priv;
2547 GList *mime_parts = NULL, *node;
2548 gchar *confirmation_message;
2552 /* TnyFolder *folder; */
2554 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2555 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2558 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2560 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2562 /* Remove already purged messages from mime parts list */
2564 while (node != NULL) {
2565 TnyMimePart *part = TNY_MIME_PART (node->data);
2566 if (tny_mime_part_is_purged (part)) {
2567 GList *deleted_node = node;
2568 node = g_list_next (node);
2569 g_object_unref (part);
2570 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2572 node = g_list_next (node);
2576 if (mime_parts == NULL)
2579 n_attachments = g_list_length (mime_parts);
2580 if (n_attachments == 1) {
2581 const gchar *filename;
2583 if (TNY_IS_MSG (mime_parts->data)) {
2585 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2586 filename = tny_header_get_subject (header);
2587 g_object_unref (header);
2588 if (filename == NULL)
2589 filename = _("mail_va_no_subject");
2591 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2593 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2595 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2596 "mcen_nc_purge_files_text",
2597 n_attachments), n_attachments);
2599 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2600 confirmation_message);
2601 g_free (confirmation_message);
2603 if (response != GTK_RESPONSE_OK)
2606 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2607 /* folder = tny_msg_get_folder (msg); */
2608 /* tny_msg_uncache_attachments (msg); */
2609 /* tny_folder_refresh (folder, NULL); */
2610 /* g_object_unref (folder); */
2612 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2613 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2614 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2617 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2618 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2619 tny_msg_rewrite_cache (msg);
2620 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2622 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2623 g_list_free (mime_parts);
2625 if (priv->purge_timeout > 0) {
2626 g_source_remove (priv->purge_timeout);
2627 priv->purge_timeout = 0;
2630 if (priv->remove_attachment_banner) {
2631 gtk_widget_destroy (priv->remove_attachment_banner);
2632 g_object_unref (priv->remove_attachment_banner);
2633 priv->remove_attachment_banner = NULL;
2641 update_window_title (ModestMsgViewWindow *window)
2643 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2645 TnyHeader *header = NULL;
2646 const gchar *subject = NULL;
2648 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2651 header = tny_msg_get_header (msg);
2652 subject = tny_header_get_subject (header);
2653 g_object_unref (msg);
2656 if ((subject == NULL)||(subject[0] == '\0'))
2657 subject = _("mail_va_no_subject");
2659 gtk_window_set_title (GTK_WINDOW (window), subject);
2663 static void on_move_focus (ModestMsgViewWindow *window,
2664 GtkDirectionType direction,
2667 GtkWidget *current_focus = NULL;
2669 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2670 if ((current_focus != NULL) &&
2671 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2672 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");