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_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_update_priority (ModestMsgViewWindow *window);
90 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
91 gboolean show_toolbar);
93 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
95 ModestMsgViewWindow *window);
96 void modest_msg_view_window_on_row_changed(
97 GtkTreeModel *header_model,
100 ModestMsgViewWindow *window);
102 void modest_msg_view_window_on_row_deleted(
103 GtkTreeModel *header_model,
105 ModestMsgViewWindow *window);
107 void modest_msg_view_window_on_row_inserted(
108 GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 void modest_msg_view_window_on_row_reordered(
114 GtkTreeModel *header_model,
118 ModestMsgViewWindow *window);
120 void modest_msg_view_window_update_model_replaced(
121 ModestHeaderViewObserver *window,
123 const gchar *tny_folder_id);
125 static void cancel_progressbar (GtkToolButton *toolbutton,
126 ModestMsgViewWindow *self);
128 static void on_queue_changed (ModestMailOperationQueue *queue,
129 ModestMailOperation *mail_op,
130 ModestMailOperationQueueNotification type,
131 ModestMsgViewWindow *self);
133 static void on_account_removed (TnyAccountStore *account_store,
137 static void on_move_focus (GtkWidget *widget,
138 GtkDirectionType direction,
141 static void view_msg_cb (ModestMailOperation *mail_op,
148 static void set_toolbar_mode (ModestMsgViewWindow *self,
149 ModestToolBarModes mode);
151 static void update_window_title (ModestMsgViewWindow *window);
153 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
154 static void init_window (ModestMsgViewWindow *obj);
157 /* list my signals */
163 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
164 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
165 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
168 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
169 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
170 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
171 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
172 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
173 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
174 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
177 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
178 struct _ModestMsgViewWindowPrivate {
181 GtkWidget *main_scroll;
182 GtkWidget *find_toolbar;
185 /* Progress observers */
186 GtkWidget *progress_bar;
187 GSList *progress_widgets;
190 GtkWidget *progress_toolitem;
191 GtkWidget *cancel_toolitem;
192 GtkWidget *prev_toolitem;
193 GtkWidget *next_toolitem;
194 ModestToolBarModes current_toolbar_mode;
196 /* Optimized view enabled */
197 gboolean optimized_view;
199 /* Whether this was created via the *_new_for_search_result() function. */
200 gboolean is_search_result;
202 /* A reference to the @model of the header view
203 * to allow selecting previous/next messages,
204 * if the message is currently selected in the header view.
206 const gchar *header_folder_id;
207 GtkTreeModel *header_model;
208 GtkTreeRowReference *row_reference;
209 GtkTreeRowReference *next_row_reference;
211 gulong clipboard_change_handler;
212 gulong queue_change_handler;
213 gulong account_removed_handler;
214 gulong row_changed_handler;
215 gulong row_deleted_handler;
216 gulong row_inserted_handler;
217 gulong rows_reordered_handler;
220 GtkWidget *remove_attachment_banner;
222 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;
414 priv->sighandlers = NULL;
417 init_window (MODEST_MSG_VIEW_WINDOW(obj));
418 /* Set window icon */
419 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
421 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
422 g_object_unref (window_icon);
426 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
427 GTK_WINDOW(obj),"applications_email_viewer");
432 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
434 ModestMsgViewWindowPrivate *priv = NULL;
436 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
438 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
440 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
442 if (priv->progress_bar_timeout > 0) {
443 g_source_remove (priv->progress_bar_timeout);
444 priv->progress_bar_timeout = 0;
451 set_toolbar_mode (ModestMsgViewWindow *self,
452 ModestToolBarModes mode)
454 ModestWindowPrivate *parent_priv;
455 ModestMsgViewWindowPrivate *priv;
456 /* GtkWidget *widget = NULL; */
458 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
460 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
461 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
463 /* Sets current toolbar mode */
464 priv->current_toolbar_mode = mode;
466 /* Update toolbar dimming state */
467 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
470 case TOOLBAR_MODE_NORMAL:
471 if (priv->progress_toolitem) {
472 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
473 gtk_widget_hide (priv->progress_toolitem);
476 if (priv->progress_bar)
477 gtk_widget_hide (priv->progress_bar);
479 if (priv->cancel_toolitem)
480 gtk_widget_hide (priv->cancel_toolitem);
482 if (priv->prev_toolitem)
483 gtk_widget_show (priv->prev_toolitem);
485 if (priv->next_toolitem)
486 gtk_widget_show (priv->next_toolitem);
488 /* Hide toolbar if optimized view is enabled */
489 if (priv->optimized_view) {
490 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
491 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
495 case TOOLBAR_MODE_TRANSFER:
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_bar)
503 gtk_widget_show (priv->progress_bar);
505 if (priv->progress_toolitem) {
506 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
507 gtk_widget_show (priv->progress_toolitem);
510 if (priv->cancel_toolitem)
511 gtk_widget_show (priv->cancel_toolitem);
513 /* Show toolbar if it's hiden (optimized view ) */
514 if (priv->optimized_view) {
515 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
516 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
521 g_return_if_reached ();
528 menubar_to_menu (GtkUIManager *ui_manager)
530 GtkWidget *main_menu;
532 /* Get the menubar from the UI manager */
533 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
539 init_window (ModestMsgViewWindow *obj)
541 GtkWidget *main_vbox;
542 ModestMsgViewWindowPrivate *priv;
543 ModestWindowPrivate *parent_priv;
545 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
546 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
548 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
549 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
550 main_vbox = gtk_vbox_new (FALSE, 6);
552 #ifdef MODEST_USE_MOZEMBED
553 priv->main_scroll = priv->msg_view;
554 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
556 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
557 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
559 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
560 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
561 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
563 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
564 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
566 priv->find_toolbar = hildon_find_toolbar_new (NULL);
567 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
568 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
570 gtk_widget_show_all (GTK_WIDGET(main_vbox));
574 modest_msg_view_window_disconnect_signals (ModestWindow *self)
576 ModestMsgViewWindowPrivate *priv;
577 ModestHeaderView *header_view = NULL;
578 ModestWindow *main_window = NULL;
580 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
582 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
583 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
584 priv->clipboard_change_handler))
585 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
586 priv->clipboard_change_handler);
588 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
589 priv->queue_change_handler))
590 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
591 priv->queue_change_handler);
593 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
594 priv->account_removed_handler))
595 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
596 priv->account_removed_handler);
598 if (priv->header_model) {
599 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
600 priv->row_changed_handler))
601 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
602 priv->row_changed_handler);
604 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
605 priv->row_deleted_handler))
606 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
607 priv->row_deleted_handler);
609 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
610 priv->row_inserted_handler))
611 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
612 priv->row_inserted_handler);
614 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
615 priv->rows_reordered_handler))
616 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
617 priv->rows_reordered_handler);
620 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
621 priv->sighandlers = NULL;
623 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
624 FALSE); /* don't create */
628 header_view = MODEST_HEADER_VIEW(
629 modest_main_window_get_child_widget(
630 MODEST_MAIN_WINDOW(main_window),
631 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
632 if (header_view == NULL)
635 modest_header_view_remove_observer(header_view,
636 MODEST_HEADER_VIEW_OBSERVER(self));
640 modest_msg_view_window_finalize (GObject *obj)
642 ModestMsgViewWindowPrivate *priv;
644 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
646 /* Sanity check: shouldn't be needed, the window mgr should
647 call this function before */
648 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
650 if (priv->header_model != NULL) {
651 g_object_unref (priv->header_model);
652 priv->header_model = NULL;
655 if (priv->progress_bar_timeout > 0) {
656 g_source_remove (priv->progress_bar_timeout);
657 priv->progress_bar_timeout = 0;
660 if (priv->remove_attachment_banner) {
661 gtk_widget_destroy (priv->remove_attachment_banner);
662 g_object_unref (priv->remove_attachment_banner);
663 priv->remove_attachment_banner = NULL;
666 if (priv->purge_timeout > 0) {
667 g_source_remove (priv->purge_timeout);
668 priv->purge_timeout = 0;
671 if (priv->row_reference) {
672 gtk_tree_row_reference_free (priv->row_reference);
673 priv->row_reference = NULL;
676 if (priv->next_row_reference) {
677 gtk_tree_row_reference_free (priv->next_row_reference);
678 priv->next_row_reference = NULL;
682 g_free (priv->msg_uid);
683 priv->msg_uid = NULL;
686 G_OBJECT_CLASS(parent_class)->finalize (obj);
690 select_next_valid_row (GtkTreeModel *model,
691 GtkTreeRowReference **row_reference,
694 GtkTreeIter tmp_iter;
695 GtkTreePath *path, *next;
696 gboolean retval = FALSE;
698 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
700 path = gtk_tree_row_reference_get_path (*row_reference);
701 gtk_tree_model_get_iter (model, &tmp_iter, path);
702 gtk_tree_row_reference_free (*row_reference);
703 *row_reference = NULL;
705 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
706 next = gtk_tree_model_get_path (model, &tmp_iter);
707 *row_reference = gtk_tree_row_reference_new (model, next);
709 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
710 next = gtk_tree_model_get_path (model, &tmp_iter);
712 /* Ensure that we are not selecting the same */
713 if (gtk_tree_path_compare (path, next) != 0) {
714 *row_reference = gtk_tree_row_reference_new (model, next);
720 gtk_tree_path_free (path);
725 /* TODO: This should be in _init(), with the parameters as properties. */
727 modest_msg_view_window_construct (ModestMsgViewWindow *self,
728 const gchar *modest_account_name,
729 const gchar *msg_uid)
732 ModestMsgViewWindowPrivate *priv = NULL;
733 ModestWindowPrivate *parent_priv = NULL;
734 ModestDimmingRulesGroup *menu_rules_group = NULL;
735 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
736 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
738 obj = G_OBJECT (self);
739 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
740 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
742 priv->msg_uid = g_strdup (msg_uid);
745 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
746 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
747 gtk_widget_show (parent_priv->menubar);
748 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
750 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
751 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
752 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
754 /* Add common dimming rules */
755 modest_dimming_rules_group_add_rules (menu_rules_group,
756 modest_msg_view_menu_dimming_entries,
757 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
758 MODEST_WINDOW (self));
759 modest_dimming_rules_group_add_rules (toolbar_rules_group,
760 modest_msg_view_toolbar_dimming_entries,
761 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
762 MODEST_WINDOW (self));
763 modest_dimming_rules_group_add_rules (clipboard_rules_group,
764 modest_msg_view_clipboard_dimming_entries,
765 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
766 MODEST_WINDOW (self));
768 /* Insert dimming rules group for this window */
769 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
770 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
771 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
772 g_object_unref (menu_rules_group);
773 g_object_unref (toolbar_rules_group);
774 g_object_unref (clipboard_rules_group);
776 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
778 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
780 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);
781 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
782 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
783 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
784 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
785 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
786 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
787 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
788 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
789 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
790 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
792 g_signal_connect (G_OBJECT (obj), "key-release-event",
793 G_CALLBACK (modest_msg_view_window_key_event),
796 g_signal_connect (G_OBJECT (obj), "key-press-event",
797 G_CALLBACK (modest_msg_view_window_key_event),
800 g_signal_connect (G_OBJECT (obj), "window-state-event",
801 G_CALLBACK (modest_msg_view_window_window_state_event),
804 g_signal_connect (G_OBJECT (obj), "move-focus",
805 G_CALLBACK (on_move_focus), obj);
807 /* Mail Operation Queue */
808 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
810 G_CALLBACK (on_queue_changed),
813 /* Account manager */
814 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
816 G_CALLBACK(on_account_removed),
819 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
821 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
822 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
823 priv->last_search = NULL;
825 /* Init the clipboard actions dim status */
826 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
828 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
830 /* Check toolbar dimming rules */
831 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
832 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
836 /* FIXME: parameter checks */
838 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
839 const gchar *modest_account_name,
840 const gchar *msg_uid,
842 GtkTreeRowReference *row_reference)
844 ModestMsgViewWindow *window = NULL;
845 ModestMsgViewWindowPrivate *priv = NULL;
846 TnyFolder *header_folder = NULL;
847 ModestHeaderView *header_view = NULL;
848 ModestWindow *main_window = NULL;
849 ModestWindowMgr *mgr = NULL;
851 mgr = modest_runtime_get_window_mgr ();
852 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
853 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
855 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
857 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
859 /* Remember the message list's TreeModel so we can detect changes
860 * and change the list selection when necessary: */
862 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
864 g_warning ("%s: BUG: no main window", __FUNCTION__);
868 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
869 MODEST_MAIN_WINDOW(main_window),
870 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
871 if (header_view != NULL){
872 header_folder = modest_header_view_get_folder(header_view);
873 g_assert(header_folder != NULL);
874 priv->header_folder_id = tny_folder_get_id(header_folder);
875 g_assert(priv->header_folder_id != NULL);
876 g_object_unref(header_folder);
879 priv->header_model = g_object_ref(model);
880 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
881 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
882 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
884 priv->row_changed_handler = g_signal_connect(
885 GTK_TREE_MODEL(model), "row-changed",
886 G_CALLBACK(modest_msg_view_window_on_row_changed),
888 priv->row_deleted_handler = g_signal_connect(
889 GTK_TREE_MODEL(model), "row-deleted",
890 G_CALLBACK(modest_msg_view_window_on_row_deleted),
892 priv->row_inserted_handler = g_signal_connect (
893 GTK_TREE_MODEL(model), "row-inserted",
894 G_CALLBACK(modest_msg_view_window_on_row_inserted),
896 priv->rows_reordered_handler = g_signal_connect(
897 GTK_TREE_MODEL(model), "rows-reordered",
898 G_CALLBACK(modest_msg_view_window_on_row_reordered),
901 if (header_view != NULL){
902 modest_header_view_add_observer(header_view,
903 MODEST_HEADER_VIEW_OBSERVER(window));
906 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
907 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
908 gtk_widget_show_all (GTK_WIDGET (window));
910 modest_msg_view_window_update_priority (window);
912 /* Check toolbar dimming rules */
913 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
915 return MODEST_WINDOW(window);
919 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
920 const gchar *modest_account_name,
921 const gchar *msg_uid)
923 ModestMsgViewWindow *window = NULL;
924 ModestMsgViewWindowPrivate *priv = NULL;
925 ModestWindowMgr *mgr = NULL;
927 mgr = modest_runtime_get_window_mgr ();
928 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
929 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
930 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
932 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
934 /* Remember that this is a search result,
935 * so we can disable some UI appropriately: */
936 priv->is_search_result = TRUE;
938 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
939 update_window_title (window);
941 return MODEST_WINDOW(window);
945 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
946 const gchar *modest_account_name,
947 const gchar *msg_uid)
950 ModestMsgViewWindowPrivate *priv;
951 ModestWindowMgr *mgr = NULL;
953 g_return_val_if_fail (msg, NULL);
954 mgr = modest_runtime_get_window_mgr ();
955 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
956 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
957 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
958 modest_account_name, msg_uid);
960 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
961 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
963 return MODEST_WINDOW(obj);
966 void modest_msg_view_window_on_row_changed(
967 GtkTreeModel *header_model,
970 ModestMsgViewWindow *window){
971 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
974 void modest_msg_view_window_on_row_deleted(
975 GtkTreeModel *header_model,
977 ModestMsgViewWindow *window){
978 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
981 /* On insertions we check if the folder still has the message we are
982 * showing or do not. If do not, we do nothing. Which means we are still
983 * not attached to any header folder and thus next/prev buttons are
984 * still dimmed. Once the message that is shown by msg-view is found, the
985 * new model of header-view will be attached and the references will be set.
986 * On each further insertions dimming rules will be checked. However
987 * this requires extra CPU time at least works.
988 * (An message might be deleted from TnyFolder and thus will not be
989 * inserted into the model again for example if it is removed by the
990 * imap server and the header view is refreshed.)
992 void modest_msg_view_window_on_row_inserted(
993 GtkTreeModel *new_model,
994 GtkTreePath *tree_path,
995 GtkTreeIter *tree_iter,
996 ModestMsgViewWindow *window){
997 ModestMsgViewWindowPrivate *priv = NULL;
998 TnyHeader *header = NULL;
1001 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1003 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1005 /* If we already has a model attached then the message shown by
1006 * msg-view is in it, and thus we do not need any actions but
1007 * to check the dimming rules.*/
1008 if(priv->header_model != NULL){
1009 gtk_tree_row_reference_free(priv->next_row_reference);
1010 priv->next_row_reference = gtk_tree_row_reference_copy(
1011 priv->row_reference);
1012 select_next_valid_row (priv->header_model,
1013 &(priv->next_row_reference), FALSE);
1014 modest_ui_actions_check_toolbar_dimming_rules (
1015 MODEST_WINDOW (window));
1019 /* Check if the newly inserted message is the same we are actually
1020 * showing. IF not, we should remain detached from the header model
1021 * and thus prev and next toolbarbuttons should remain dimmed. */
1022 gtk_tree_model_get (new_model, tree_iter,
1023 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1024 uid = modest_tny_folder_get_header_unique_id(header);
1025 g_object_unref(G_OBJECT(header));
1027 if(!g_str_equal(priv->msg_uid, uid)){
1033 /* Setup row_reference for the actual msg. */
1034 priv->row_reference = gtk_tree_row_reference_new(
1035 new_model, tree_path);
1036 if(priv->row_reference == NULL){
1037 g_warning("No reference for msg header item.");
1041 /* Attach new_model and connect some callback to it to become able
1042 * to detect changes in header-view. */
1043 priv->header_model = g_object_ref(new_model);
1044 g_signal_connect (new_model, "row-changed",
1045 G_CALLBACK (modest_msg_view_window_on_row_changed),
1047 g_signal_connect (new_model, "row-deleted",
1048 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1050 g_signal_connect (new_model, "rows-reordered",
1051 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1054 /* Now set up next_row_reference. */
1055 priv->next_row_reference = gtk_tree_row_reference_copy(
1056 priv->row_reference);
1057 select_next_valid_row (priv->header_model,
1058 &(priv->next_row_reference), FALSE);
1060 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1063 void modest_msg_view_window_on_row_reordered(
1064 GtkTreeModel *header_model,
1068 ModestMsgViewWindow *window){
1069 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1072 /* The modest_msg_view_window_update_model_replaced implements update
1073 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1074 * actually belongs to the header-view is the same as the TnyFolder of
1075 * the message of msg-view or not. If they are different, there is
1076 * nothing to do. If they are the same, then the model has replaced and
1077 * the reference in msg-view shall be replaced from the old model to
1078 * the new model. In this case the view will be detached from it's
1079 * header folder. From this point the next/prev buttons are dimmed.
1081 void modest_msg_view_window_update_model_replaced(
1082 ModestHeaderViewObserver *observer,
1083 GtkTreeModel *model,
1084 const gchar *tny_folder_id){
1085 ModestMsgViewWindowPrivate *priv = NULL;
1086 ModestMsgViewWindow *window = NULL;
1088 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1089 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1091 window = MODEST_MSG_VIEW_WINDOW(observer);
1092 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1094 /* If there is an other folder in the header-view then we do
1095 * not care about it's model (msg list). Else if the
1096 * header-view shows the folder the msg shown by us is in, we
1097 * shall replace our model reference and make some check. */
1098 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1101 /* Model is changed(replaced), so we should forget the old
1102 * one. Because there might be other references and there
1103 * might be some change on the model even if we unreferenced
1104 * it, we need to disconnect our signals here. */
1105 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1106 priv->row_changed_handler))
1107 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1108 priv->row_changed_handler);
1109 priv->row_changed_handler = 0;
1110 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1111 priv->row_deleted_handler))
1112 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1113 priv->row_deleted_handler);
1114 priv->row_deleted_handler = 0;
1115 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1116 priv->row_inserted_handler))
1117 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1118 priv->row_inserted_handler);
1119 priv->row_inserted_handler = 0;
1120 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1121 priv->rows_reordered_handler))
1122 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1123 priv->rows_reordered_handler);
1124 priv->rows_reordered_handler = 0;
1125 g_object_unref(priv->header_model);
1126 priv->header_model = NULL;
1127 g_object_unref(priv->row_reference);
1128 priv->row_reference = NULL;
1129 g_object_unref(priv->next_row_reference);
1130 priv->next_row_reference = NULL;
1132 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1134 g_assert(model != NULL);
1136 /* Also we must connect to the new model for row insertions.
1137 * Only for insertions now. We will need other ones only after
1138 * the msg is show by msg-view is added to the new model. */
1139 priv->row_inserted_handler = g_signal_connect (
1140 model, "row-inserted",
1141 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1146 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1148 ModestMsgViewWindowPrivate *priv= NULL;
1150 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1151 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1153 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1157 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1159 ModestMsgViewWindowPrivate *priv= NULL;
1161 TnyHeader *header = NULL;
1162 GtkTreePath *path = NULL;
1165 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1166 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1168 /* If the message was not obtained from a treemodel,
1169 * for instance if it was opened directly by the search UI:
1171 if (priv->header_model == NULL) {
1172 msg = modest_msg_view_window_get_message (self);
1174 header = tny_msg_get_header (msg);
1175 g_object_unref (msg);
1180 /* Get iter of the currently selected message in the header view: */
1181 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1182 * instead of sometimes retrieving it from the header view?
1183 * Then we wouldn't be dependent on the message actually still being selected
1184 * in the header view. murrayc. */
1185 if (!gtk_tree_row_reference_valid (priv->row_reference))
1187 path = gtk_tree_row_reference_get_path (priv->row_reference);
1188 g_return_val_if_fail (path != NULL, NULL);
1189 gtk_tree_model_get_iter (priv->header_model,
1193 /* Get current message header */
1194 gtk_tree_model_get (priv->header_model, &iter,
1195 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1198 gtk_tree_path_free (path);
1203 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1205 ModestMsgViewWindowPrivate *priv;
1207 g_return_val_if_fail (self, NULL);
1209 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1211 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1215 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1217 ModestMsgViewWindowPrivate *priv;
1219 g_return_val_if_fail (self, NULL);
1221 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1223 return (const gchar*) priv->msg_uid;
1227 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1230 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1231 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1232 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1236 is_active = gtk_toggle_action_get_active (toggle);
1239 gtk_widget_show (priv->find_toolbar);
1240 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1242 gtk_widget_hide (priv->find_toolbar);
1245 /* update the toggle buttons status */
1246 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1247 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1248 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1249 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1254 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1255 ModestMsgViewWindow *obj)
1257 GtkToggleAction *toggle;
1258 ModestWindowPrivate *parent_priv;
1259 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1261 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1262 gtk_toggle_action_set_active (toggle, FALSE);
1266 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1267 ModestMsgViewWindow *obj)
1269 gchar *current_search;
1270 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1272 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1273 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1277 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1279 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1280 g_free (current_search);
1281 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1285 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1287 g_free (priv->last_search);
1288 priv->last_search = g_strdup (current_search);
1289 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1292 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1293 g_free (priv->last_search);
1294 priv->last_search = NULL;
1296 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1299 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1300 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1301 g_free (priv->last_search);
1302 priv->last_search = NULL;
1304 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1308 g_free (current_search);
1313 modest_msg_view_window_set_zoom (ModestWindow *window,
1316 ModestMsgViewWindowPrivate *priv;
1317 ModestWindowPrivate *parent_priv;
1318 GtkAction *action = NULL;
1319 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1321 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1323 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1324 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1325 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1327 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1328 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1330 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1334 modest_msg_view_window_get_zoom (ModestWindow *window)
1336 ModestMsgViewWindowPrivate *priv;
1338 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1340 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1341 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1345 modest_msg_view_window_zoom_plus (ModestWindow *window)
1347 ModestWindowPrivate *parent_priv;
1348 GtkRadioAction *zoom_radio_action;
1349 GSList *group, *node;
1351 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1352 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1353 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1355 group = gtk_radio_action_get_group (zoom_radio_action);
1357 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1358 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1362 for (node = group; node != NULL; node = g_slist_next (node)) {
1363 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1364 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1372 modest_msg_view_window_zoom_minus (ModestWindow *window)
1374 ModestWindowPrivate *parent_priv;
1375 GtkRadioAction *zoom_radio_action;
1376 GSList *group, *node;
1378 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1379 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1380 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1382 group = gtk_radio_action_get_group (zoom_radio_action);
1384 for (node = group; node != NULL; node = g_slist_next (node)) {
1385 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1386 if (node->next != NULL) {
1387 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1390 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1400 modest_msg_view_window_key_event (GtkWidget *window,
1405 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1406 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1407 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1408 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1409 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1410 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1411 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1412 gboolean return_value;
1414 if (event->type == GDK_KEY_RELEASE) {
1415 GtkScrollType scroll_type;
1417 switch (event->keyval) {
1420 scroll_type = GTK_SCROLL_STEP_UP; break;
1423 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1425 case GDK_KP_Page_Up:
1426 scroll_type = GTK_SCROLL_PAGE_UP; break;
1428 case GDK_KP_Page_Down:
1429 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1432 scroll_type = GTK_SCROLL_START; break;
1435 scroll_type = GTK_SCROLL_END; break;
1436 default: scroll_type = GTK_SCROLL_NONE;
1439 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1440 scroll_type, FALSE, &return_value);
1451 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1454 ModestMsgViewWindowPrivate *priv;
1455 GtkTreeIter tmp_iter;
1456 gboolean is_last_selected;
1458 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1459 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1461 /*if no model (so no rows at all), then virtually we are the last*/
1462 if (!priv->header_model)
1465 path = gtk_tree_row_reference_get_path (priv->row_reference);
1469 is_last_selected = TRUE;
1470 while (is_last_selected) {
1472 gtk_tree_path_next (path);
1473 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1475 gtk_tree_model_get (priv->header_model, &tmp_iter,
1476 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1479 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1480 is_last_selected = FALSE;
1481 g_object_unref(G_OBJECT(header));
1484 gtk_tree_path_free (path);
1485 return is_last_selected;
1489 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1491 ModestMsgViewWindowPrivate *priv;
1493 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1494 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1496 return priv->header_model != NULL;
1500 modest_msg_view_window_is_search_result (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->is_search_result;
1511 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1514 ModestMsgViewWindowPrivate *priv;
1515 gboolean is_first_selected;
1516 GtkTreeIter tmp_iter;
1517 /* gchar * path_string;*/
1519 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1520 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1522 /*if no model (so no rows at all), then virtually we are the first*/
1523 if (!priv->header_model)
1526 path = gtk_tree_row_reference_get_path (priv->row_reference);
1530 /* path_string = gtk_tree_path_to_string (path);
1531 is_first_selected = strcmp (path_string, "0");
1533 g_free (path_string);
1534 gtk_tree_path_free (path);
1536 return is_first_selected;*/
1538 is_first_selected = TRUE;
1539 while (is_first_selected) {
1541 if(!gtk_tree_path_prev (path))
1543 /* Here the 'if' is needless for logic, but let make sure
1544 * iter is valid for gtk_tree_model_get. */
1545 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1547 gtk_tree_model_get (priv->header_model, &tmp_iter,
1548 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1551 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1552 is_first_selected = FALSE;
1553 g_object_unref(G_OBJECT(header));
1556 gtk_tree_path_free (path);
1557 return is_first_selected;
1561 * Reads the message whose summary item is @header. It takes care of
1562 * several things, among others:
1564 * If the message was not previously downloaded then ask the user
1565 * before downloading. If there is no connection launch the connection
1566 * dialog. Update toolbar dimming rules.
1568 * Returns: TRUE if the mail operation was started, otherwise if the
1569 * user do not want to download the message, or if the user do not
1570 * want to connect, then the operation is not issued
1573 message_reader (ModestMsgViewWindow *window,
1574 ModestMsgViewWindowPrivate *priv,
1576 GtkTreeRowReference *row_reference)
1578 ModestMailOperation *mail_op = NULL;
1579 gboolean already_showing = FALSE;
1580 ModestWindow *msg_window = NULL;
1581 ModestWindowMgr *mgr;
1583 g_return_val_if_fail (row_reference != NULL, FALSE);
1585 mgr = modest_runtime_get_window_mgr ();
1586 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1587 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1590 gtk_window_present (GTK_WINDOW (msg_window));
1591 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1595 /* Msg download completed */
1596 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1597 /* Ask the user if he wants to download the message if
1599 if (!tny_device_is_online (modest_runtime_get_device())) {
1600 TnyFolder *folder = NULL;
1601 GtkResponseType response;
1603 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1604 _("mcen_nc_get_msg"));
1605 if (response == GTK_RESPONSE_CANCEL)
1608 /* Offer the connection dialog if necessary */
1609 folder = tny_header_get_folder (header);
1611 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1612 TNY_FOLDER_STORE (folder))) {
1613 g_object_unref (folder);
1616 g_object_unref (folder);
1621 /* New mail operation */
1622 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1623 modest_ui_actions_get_msgs_full_error_handler,
1626 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1627 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1628 g_object_unref (mail_op);
1630 /* Update toolbar dimming rules */
1631 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1637 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1639 ModestMsgViewWindowPrivate *priv;
1640 GtkTreePath *path= NULL;
1641 GtkTreeIter tmp_iter;
1643 gboolean retval = TRUE;
1644 GtkTreeRowReference *row_reference = NULL;
1646 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1647 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1649 /* Update the next row reference if it's not valid. This could
1650 happen if for example the header which it was pointing to,
1651 was deleted. The best place to do it is in the row-deleted
1652 handler but the tinymail model do not work like the glib
1653 tree models and reports the deletion when the row is still
1655 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1656 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1657 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1658 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1661 if (priv->next_row_reference)
1662 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1666 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1668 gtk_tree_model_get_iter (priv->header_model,
1671 gtk_tree_path_free (path);
1673 gtk_tree_model_get (priv->header_model, &tmp_iter,
1674 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1677 /* Read the message & show it */
1678 if (!message_reader (window, priv, header, row_reference)) {
1680 gtk_tree_row_reference_free (row_reference);
1684 g_object_unref (header);
1690 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1692 ModestMsgViewWindowPrivate *priv = NULL;
1693 TnyHeader *header = NULL;
1695 GtkTreePath *path = NULL;
1696 GtkTreeRowReference *row_reference = NULL;
1698 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1699 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1701 /* Check that the model is not empty */
1702 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1705 /* Get the header */
1706 gtk_tree_model_get (priv->header_model,
1708 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1710 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1711 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1712 g_object_unref (header);
1713 return modest_msg_view_window_select_next_message (self);
1716 path = gtk_tree_model_get_path (priv->header_model, &iter);
1717 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1718 gtk_tree_path_free (path);
1720 /* Read the message & show it */
1721 message_reader (self, priv, header, row_reference);
1724 g_object_unref (header);
1730 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1732 ModestMsgViewWindowPrivate *priv = NULL;
1734 GtkTreeRowReference *row_reference = NULL;
1736 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1737 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1739 /* Return inmediatly if there is no header model */
1740 if (!priv->header_model)
1743 path = gtk_tree_row_reference_get_path (priv->row_reference);
1744 while (gtk_tree_path_prev (path)) {
1748 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1749 gtk_tree_model_get (priv->header_model, &iter,
1750 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1754 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1755 g_object_unref (header);
1759 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1760 /* Read the message & show it */
1761 if (!message_reader (window, priv, header, row_reference)) {
1762 gtk_tree_row_reference_free (row_reference);
1763 g_object_unref (header);
1767 gtk_tree_path_free (path);
1768 g_object_unref (header);
1773 gtk_tree_path_free (path);
1778 view_msg_cb (ModestMailOperation *mail_op,
1785 ModestMsgViewWindow *self = NULL;
1786 ModestMsgViewWindowPrivate *priv = NULL;
1787 GtkTreeRowReference *row_reference = NULL;
1789 /* If there was any error */
1790 row_reference = (GtkTreeRowReference *) user_data;
1791 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1792 gtk_tree_row_reference_free (row_reference);
1796 /* Get the window */
1797 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1798 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1799 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1801 /* Update the row reference */
1802 gtk_tree_row_reference_free (priv->row_reference);
1803 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1804 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1805 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1806 gtk_tree_row_reference_free (row_reference);
1808 /* Mark header as read */
1809 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1810 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1812 /* Set new message */
1813 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1814 modest_msg_view_window_update_priority (self);
1815 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1816 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1818 /* Set the new message uid of the window */
1819 if (priv->msg_uid) {
1820 g_free (priv->msg_uid);
1821 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1824 /* Notify the observers */
1825 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1826 0, priv->header_model, priv->row_reference);
1828 /* Free new references */
1829 g_object_unref (self);
1833 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1835 ModestMsgViewWindowPrivate *priv;
1837 TnyFolderType folder_type;
1839 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1841 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1843 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1847 folder = tny_msg_get_folder (msg);
1849 folder_type = tny_folder_get_folder_type (folder);
1850 g_object_unref (folder);
1852 g_object_unref (msg);
1860 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1862 ModestMsgViewWindowPrivate *priv;
1863 TnyHeaderFlags flags = 0;
1865 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1867 if (priv->header_model) {
1870 GtkTreePath *path = NULL;
1872 path = gtk_tree_row_reference_get_path (priv->row_reference);
1873 g_return_if_fail (path != NULL);
1874 gtk_tree_model_get_iter (priv->header_model,
1876 gtk_tree_row_reference_get_path (priv->row_reference));
1878 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1881 flags = tny_header_get_flags (header);
1882 g_object_unref(G_OBJECT(header));
1884 gtk_tree_path_free (path);
1887 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1892 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1894 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1895 ModestWindowPrivate *parent_priv;
1896 ModestWindowMgr *mgr;
1897 gboolean is_fullscreen;
1898 GtkAction *fs_toggle_action;
1901 mgr = modest_runtime_get_window_mgr ();
1902 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1904 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1906 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1907 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1908 if (is_fullscreen != active) {
1909 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1918 set_homogeneous (GtkWidget *widget,
1921 if (GTK_IS_TOOL_ITEM (widget)) {
1922 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1923 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1928 modest_msg_view_window_show_toolbar (ModestWindow *self,
1929 gboolean show_toolbar)
1931 ModestMsgViewWindowPrivate *priv = NULL;
1932 ModestWindowPrivate *parent_priv;
1933 GtkWidget *reply_button = NULL, *menu = NULL;
1934 GtkWidget *placeholder = NULL;
1936 const gchar *action_name;
1939 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1940 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1942 /* Set optimized view status */
1943 priv->optimized_view = !show_toolbar;
1945 if (!parent_priv->toolbar) {
1946 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1948 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1950 /* Set homogeneous toolbar */
1951 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1952 set_homogeneous, NULL);
1954 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1955 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1956 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1957 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1958 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1959 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1960 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1961 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1963 /* Add ProgressBar (Transfer toolbar) */
1964 priv->progress_bar = modest_progress_bar_widget_new ();
1965 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1966 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1967 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1968 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1969 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1971 /* Connect cancel 'clicked' signal to abort progress mode */
1972 g_signal_connect(priv->cancel_toolitem, "clicked",
1973 G_CALLBACK(cancel_progressbar),
1976 /* Add it to the observers list */
1977 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1980 hildon_window_add_toolbar (HILDON_WINDOW (self),
1981 GTK_TOOLBAR (parent_priv->toolbar));
1983 /* Set reply button tap and hold menu */
1984 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1985 "/ToolBar/ToolbarMessageReply");
1986 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1987 "/ToolbarReplyCSM");
1988 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1992 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1993 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1994 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1996 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1997 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
1998 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2000 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2003 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2004 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2007 /* Update also the actions (to update the toggles in the
2008 menus), we have to do it manually because some other window
2009 of the same time could have changed it (remember that the
2010 toolbar fullscreen mode is shared by all the windows of the
2012 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2013 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2015 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2017 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2018 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2023 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2025 ModestMsgViewWindow *window)
2027 if (!GTK_WIDGET_VISIBLE (window))
2030 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2034 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2036 ModestMsgViewWindowPrivate *priv;
2038 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2039 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2041 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2045 cancel_progressbar (GtkToolButton *toolbutton,
2046 ModestMsgViewWindow *self)
2049 ModestMsgViewWindowPrivate *priv;
2051 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2053 /* Get operation observers and cancel its current operation */
2054 tmp = priv->progress_widgets;
2056 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2057 tmp=g_slist_next(tmp);
2061 observers_empty (ModestMsgViewWindow *self)
2064 ModestMsgViewWindowPrivate *priv;
2065 gboolean is_empty = TRUE;
2066 guint pending_ops = 0;
2068 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2069 tmp = priv->progress_widgets;
2071 /* Check all observers */
2072 while (tmp && is_empty) {
2073 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2074 is_empty = pending_ops == 0;
2076 tmp = g_slist_next(tmp);
2083 on_account_removed (TnyAccountStore *account_store,
2084 TnyAccount *account,
2087 /* Do nothing if it's a transport account, because we only
2088 show the messages of a store account */
2089 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2090 const gchar *parent_acc = NULL;
2091 const gchar *our_acc = NULL;
2093 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2094 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2096 /* Close this window if I'm showing a message of the removed account */
2097 if (strcmp (parent_acc, our_acc) == 0)
2098 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2103 on_mail_operation_started (ModestMailOperation *mail_op,
2106 ModestMsgViewWindow *self;
2107 ModestMailOperationTypeOperation op_type;
2109 ModestMsgViewWindowPrivate *priv;
2111 self = MODEST_MSG_VIEW_WINDOW (user_data);
2112 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2113 op_type = modest_mail_operation_get_type_operation (mail_op);
2114 tmp = priv->progress_widgets;
2116 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2117 set_toolbar_transfer_mode(self);
2119 modest_progress_object_add_operation (
2120 MODEST_PROGRESS_OBJECT (tmp->data),
2122 tmp = g_slist_next (tmp);
2128 on_mail_operation_finished (ModestMailOperation *mail_op,
2131 ModestMsgViewWindow *self;
2132 ModestMailOperationTypeOperation op_type;
2134 ModestMsgViewWindowPrivate *priv;
2136 self = MODEST_MSG_VIEW_WINDOW (user_data);
2137 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2138 op_type = modest_mail_operation_get_type_operation (mail_op);
2139 tmp = priv->progress_widgets;
2141 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2143 modest_progress_object_remove_operation (
2144 MODEST_PROGRESS_OBJECT (tmp->data),
2146 tmp = g_slist_next (tmp);
2149 /* If no more operations are being observed, NORMAL mode is enabled again */
2150 if (observers_empty (self)) {
2151 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2157 on_queue_changed (ModestMailOperationQueue *queue,
2158 ModestMailOperation *mail_op,
2159 ModestMailOperationQueueNotification type,
2160 ModestMsgViewWindow *self)
2162 ModestMsgViewWindowPrivate *priv;
2164 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2166 /* If this operations was created by another window, do nothing */
2167 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2170 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2171 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2173 "operation-started",
2174 G_CALLBACK (on_mail_operation_started),
2176 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2178 "operation-finished",
2179 G_CALLBACK (on_mail_operation_finished),
2181 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2182 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2184 "operation-started");
2185 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2187 "operation-finished");
2192 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2194 ModestMsgViewWindowPrivate *priv;
2195 GList *selected_attachments = NULL;
2197 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2198 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2200 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2202 return selected_attachments;
2206 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2208 ModestMsgViewWindowPrivate *priv;
2209 const gchar *msg_uid;
2210 gchar *attachment_uid = NULL;
2211 gint attachment_index = 0;
2214 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2215 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2216 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2218 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2219 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2220 attachment_index = g_list_index (attachments, mime_part);
2221 g_list_free (attachments);
2223 if (msg_uid && attachment_index >= 0) {
2224 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2227 if (mime_part == NULL) {
2228 gboolean error = FALSE;
2229 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2230 if (selected_attachments == NULL) {
2232 } else if (g_list_length (selected_attachments) > 1) {
2233 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2236 mime_part = (TnyMimePart *) selected_attachments->data;
2237 g_object_ref (mime_part);
2239 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2240 g_list_free (selected_attachments);
2245 g_object_ref (mime_part);
2248 if (tny_mime_part_is_purged (mime_part)) {
2249 g_object_unref (mime_part);
2253 if (!TNY_IS_MSG (mime_part)) {
2254 gchar *filepath = NULL;
2255 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2256 const gchar *content_type;
2257 TnyFsStream *temp_stream = NULL;
2258 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid,
2261 if (temp_stream != NULL) {
2262 content_type = tny_mime_part_get_content_type (mime_part);
2263 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2265 /* make the file read-only */
2266 if (g_chmod(filepath, 0444) != 0)
2267 g_warning ("%s: failed to set file '%s' to read-only: %s",
2268 __FUNCTION__, filepath, strerror(errno));
2270 modest_platform_activate_file (filepath, content_type);
2271 g_object_unref (temp_stream);
2273 /* NOTE: files in the temporary area will be automatically
2274 * cleaned after some time if they are no longer in use */
2275 } else if (filepath != NULL) {
2276 /* the file may already exist but it isn't writable,
2277 * let's try to open it anyway */
2278 content_type = tny_mime_part_get_content_type (mime_part);
2279 modest_platform_activate_file (filepath, content_type);
2283 /* message attachment */
2284 TnyHeader *header = NULL;
2285 ModestWindowMgr *mgr;
2286 ModestWindow *msg_win = NULL;
2289 header = tny_msg_get_header (TNY_MSG (mime_part));
2290 mgr = modest_runtime_get_window_mgr ();
2291 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2294 if (msg_win) /* there is already a window for this uid; top it */
2295 gtk_window_present (GTK_WINDOW(msg_win));
2297 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2298 * thus, we don't do anything */
2299 g_warning ("window for is already being created");
2301 /* it's not found, so create a new window for it */
2302 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2303 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2305 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2306 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2307 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2308 modest_window_get_zoom (MODEST_WINDOW (window)));
2309 modest_window_mgr_register_window (mgr, msg_win);
2310 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2311 gtk_widget_show_all (GTK_WIDGET (msg_win));
2314 g_object_unref (mime_part);
2330 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2331 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2332 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2333 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2336 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2340 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2341 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2342 g_free (pair->filename);
2343 g_object_unref (pair->part);
2344 g_slice_free (SaveMimePartPair, pair);
2346 g_list_free (info->pairs);
2349 gtk_widget_destroy (info->banner);
2350 g_object_unref (info->banner);
2351 g_slice_free (SaveMimePartInfo, info);
2356 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2358 if (info->pairs != NULL) {
2359 save_mime_part_to_file (info);
2362 result = info->result;
2364 /* This is a GDK lock because we are an idle callback and
2365 * hildon_banner_show_information is or does Gtk+ code */
2367 gdk_threads_enter (); /* CHECKED */
2368 save_mime_part_info_free (info, TRUE);
2370 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2372 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2374 gdk_threads_leave (); /* CHECKED */
2381 save_mime_part_to_file (SaveMimePartInfo *info)
2383 GnomeVFSResult result;
2384 GnomeVFSHandle *handle;
2386 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2388 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2389 if (result == GNOME_VFS_OK) {
2390 stream = tny_vfs_stream_new (handle);
2391 tny_mime_part_decode_to_stream (pair->part, stream);
2392 g_object_unref (G_OBJECT (stream));
2393 g_object_unref (pair->part);
2394 g_slice_free (SaveMimePartPair, pair);
2395 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2396 info->result = TRUE;
2398 save_mime_part_info_free (info, FALSE);
2399 info->result = FALSE;
2402 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2407 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2409 gboolean is_ok = TRUE;
2410 gint replaced_files = 0;
2411 const GList *files = info->pairs;
2414 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2415 SaveMimePartPair *pair = iter->data;
2416 if (modest_maemo_utils_file_exists (pair->filename)) {
2420 if (replaced_files) {
2421 GtkWidget *confirm_overwrite_dialog;
2422 const gchar *message = (replaced_files == 1) ?
2423 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2424 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2425 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2428 gtk_widget_destroy (confirm_overwrite_dialog);
2432 save_mime_part_info_free (info, TRUE);
2434 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2435 _CS("sfil_ib_saving"));
2436 info->banner = g_object_ref (banner);
2437 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2438 g_object_unref (banner);
2445 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2447 gboolean clean_list = FALSE;
2448 ModestMsgViewWindowPrivate *priv;
2449 GList *files_to_save = NULL;
2450 GtkWidget *save_dialog = NULL;
2451 gchar *folder = NULL;
2452 gboolean canceled = FALSE;
2453 const gchar *filename = NULL;
2454 gchar *save_multiple_str = NULL;
2456 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2457 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2459 if (mime_parts == NULL) {
2460 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2461 if (mime_parts == NULL)
2466 /* prepare dialog */
2467 if (mime_parts->next == NULL) {
2468 /* only one attachment selected */
2469 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2470 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2471 filename = tny_mime_part_get_filename (mime_part);
2473 g_warning ("Tried to save a non-file attachment");
2477 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2478 g_list_length (mime_parts));
2481 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2482 GTK_FILE_CHOOSER_ACTION_SAVE);
2485 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2486 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2490 if (filename != NULL)
2491 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2494 /* if multiple, set multiple string */
2495 if (save_multiple_str) {
2496 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2500 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2501 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2503 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2504 hildon_banner_show_information
2505 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2509 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2510 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2512 if (tny_mime_part_is_attachment (mime_part)) {
2513 SaveMimePartPair *pair;
2515 if ((mime_parts->next != NULL) &&
2516 (tny_mime_part_get_filename (mime_part) == NULL))
2519 pair = g_slice_new0 (SaveMimePartPair);
2520 if (mime_parts->next == NULL) {
2521 pair->filename = g_strdup (chooser_uri);
2524 g_build_filename (chooser_uri,
2525 tny_mime_part_get_filename (mime_part), NULL);
2527 pair->part = g_object_ref (mime_part);
2528 files_to_save = g_list_prepend (files_to_save, pair);
2532 g_free (chooser_uri);
2535 gtk_widget_destroy (save_dialog);
2538 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2539 g_list_free (mime_parts);
2542 if (files_to_save != NULL) {
2543 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2544 info->pairs = files_to_save;
2545 info->result = TRUE;
2546 save_mime_parts_to_file_with_checks (info);
2551 show_remove_attachment_information (gpointer userdata)
2553 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2554 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2556 /* We're outside the main lock */
2557 gdk_threads_enter ();
2559 if (priv->remove_attachment_banner != NULL) {
2560 gtk_widget_destroy (priv->remove_attachment_banner);
2561 g_object_unref (priv->remove_attachment_banner);
2564 priv->remove_attachment_banner = g_object_ref (
2565 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2567 gdk_threads_leave ();
2573 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2575 ModestMsgViewWindowPrivate *priv;
2576 GList *mime_parts = NULL, *node;
2577 gchar *confirmation_message;
2581 /* TnyFolder *folder; */
2583 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2584 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2587 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2589 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2591 /* Remove already purged messages from mime parts list */
2593 while (node != NULL) {
2594 TnyMimePart *part = TNY_MIME_PART (node->data);
2595 if (tny_mime_part_is_purged (part)) {
2596 GList *deleted_node = node;
2597 node = g_list_next (node);
2598 g_object_unref (part);
2599 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2601 node = g_list_next (node);
2605 if (mime_parts == NULL)
2608 n_attachments = g_list_length (mime_parts);
2609 if (n_attachments == 1) {
2610 const gchar *filename;
2612 if (TNY_IS_MSG (mime_parts->data)) {
2614 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2615 filename = tny_header_get_subject (header);
2616 g_object_unref (header);
2617 if (filename == NULL)
2618 filename = _("mail_va_no_subject");
2620 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2622 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2624 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2625 "mcen_nc_purge_files_text",
2626 n_attachments), n_attachments);
2628 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2629 confirmation_message);
2630 g_free (confirmation_message);
2632 if (response != GTK_RESPONSE_OK)
2635 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2636 /* folder = tny_msg_get_folder (msg); */
2637 /* tny_msg_uncache_attachments (msg); */
2638 /* tny_folder_refresh (folder, NULL); */
2639 /* g_object_unref (folder); */
2641 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2642 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2643 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2646 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2647 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2648 tny_msg_rewrite_cache (msg);
2649 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2651 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2652 g_list_free (mime_parts);
2654 if (priv->purge_timeout > 0) {
2655 g_source_remove (priv->purge_timeout);
2656 priv->purge_timeout = 0;
2659 if (priv->remove_attachment_banner) {
2660 gtk_widget_destroy (priv->remove_attachment_banner);
2661 g_object_unref (priv->remove_attachment_banner);
2662 priv->remove_attachment_banner = NULL;
2670 update_window_title (ModestMsgViewWindow *window)
2672 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2674 TnyHeader *header = NULL;
2675 const gchar *subject = NULL;
2677 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2680 header = tny_msg_get_header (msg);
2681 subject = tny_header_get_subject (header);
2682 g_object_unref (msg);
2685 if ((subject == NULL)||(subject[0] == '\0'))
2686 subject = _("mail_va_no_subject");
2688 gtk_window_set_title (GTK_WINDOW (window), subject);
2692 static void on_move_focus (GtkWidget *widget,
2693 GtkDirectionType direction,
2696 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");