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-utils.h>
39 #include <modest-maemo-utils.h>
40 #include <modest-tny-msg.h>
41 #include <modest-msg-view-window.h>
42 #include <modest-attachments-view.h>
43 #include <modest-main-window-ui.h>
44 #include "modest-msg-view-window-ui-dimming.h"
45 #include <modest-widget-memory.h>
46 #include <modest-runtime.h>
47 #include <modest-window-priv.h>
48 #include <modest-tny-folder.h>
49 #include <modest-text-utils.h>
50 #include <modest-account-mgr-helpers.h>
51 #include "modest-progress-bar-widget.h"
52 #include "modest-defs.h"
53 #include "modest-hildon-includes.h"
54 #include "modest-ui-dimming-manager.h"
55 #include <gdk/gdkkeysyms.h>
56 #include <modest-tny-account.h>
57 #include <modest-mime-part-view.h>
58 #include <modest-isearch-view.h>
61 #include <glib/gstdio.h>
63 #define DEFAULT_FOLDER "MyDocs/.documents"
65 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
66 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
67 static void modest_header_view_observer_init(
68 ModestHeaderViewObserverIface *iface_class);
69 static void modest_msg_view_window_finalize (GObject *obj);
70 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
72 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
73 ModestMsgViewWindow *obj);
74 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
75 ModestMsgViewWindow *obj);
77 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
78 static void modest_msg_view_window_set_zoom (ModestWindow *window,
80 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
81 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
82 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
83 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
86 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
87 GdkEventWindowState *event,
89 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
91 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
92 gboolean show_toolbar);
94 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
96 ModestMsgViewWindow *window);
97 void modest_msg_view_window_on_row_changed(
98 GtkTreeModel *header_model,
101 ModestMsgViewWindow *window);
103 void modest_msg_view_window_on_row_deleted(
104 GtkTreeModel *header_model,
106 ModestMsgViewWindow *window);
108 void modest_msg_view_window_on_row_inserted(
109 GtkTreeModel *header_model,
110 GtkTreePath *tree_path,
111 GtkTreeIter *tree_iter,
112 ModestMsgViewWindow *window);
114 void modest_msg_view_window_on_row_reordered(
115 GtkTreeModel *header_model,
119 ModestMsgViewWindow *window);
121 void modest_msg_view_window_update_model_replaced(
122 ModestHeaderViewObserver *window,
124 const gchar *tny_folder_id);
126 static void cancel_progressbar (GtkToolButton *toolbutton,
127 ModestMsgViewWindow *self);
129 static void on_queue_changed (ModestMailOperationQueue *queue,
130 ModestMailOperation *mail_op,
131 ModestMailOperationQueueNotification type,
132 ModestMsgViewWindow *self);
134 static void on_account_removed (TnyAccountStore *account_store,
138 static void on_move_focus (GtkWidget *widget,
139 GtkDirectionType direction,
142 static void view_msg_cb (ModestMailOperation *mail_op,
149 static void set_toolbar_mode (ModestMsgViewWindow *self,
150 ModestToolBarModes mode);
152 static void update_window_title (ModestMsgViewWindow *window);
154 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
155 static void init_window (ModestMsgViewWindow *obj);
158 /* list my signals */
164 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
165 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
166 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
169 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
170 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
171 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
172 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
173 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
174 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
175 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
178 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
179 struct _ModestMsgViewWindowPrivate {
182 GtkWidget *main_scroll;
183 GtkWidget *find_toolbar;
186 /* Progress observers */
187 GtkWidget *progress_bar;
188 GSList *progress_widgets;
191 GtkWidget *progress_toolitem;
192 GtkWidget *cancel_toolitem;
193 GtkWidget *prev_toolitem;
194 GtkWidget *next_toolitem;
195 ModestToolBarModes current_toolbar_mode;
197 /* Optimized view enabled */
198 gboolean optimized_view;
200 /* Whether this was created via the *_new_for_search_result() function. */
201 gboolean is_search_result;
203 /* A reference to the @model of the header view
204 * to allow selecting previous/next messages,
205 * if the message is currently selected in the header view.
207 const gchar *header_folder_id;
208 GtkTreeModel *header_model;
209 GtkTreeRowReference *row_reference;
210 GtkTreeRowReference *next_row_reference;
212 gulong clipboard_change_handler;
213 gulong queue_change_handler;
214 gulong account_removed_handler;
215 gulong row_changed_handler;
216 gulong row_deleted_handler;
217 gulong row_inserted_handler;
218 gulong rows_reordered_handler;
221 GtkWidget *remove_attachment_banner;
223 guint progress_bar_timeout;
230 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
231 MODEST_TYPE_MSG_VIEW_WINDOW, \
232 ModestMsgViewWindowPrivate))
234 static GtkWindowClass *parent_class = NULL;
236 /* uncomment the following if you have defined any signals */
237 static guint signals[LAST_SIGNAL] = {0};
240 modest_msg_view_window_get_type (void)
242 static GType my_type = 0;
244 static const GTypeInfo my_info = {
245 sizeof(ModestMsgViewWindowClass),
246 NULL, /* base init */
247 NULL, /* base finalize */
248 (GClassInitFunc) modest_msg_view_window_class_init,
249 NULL, /* class finalize */
250 NULL, /* class data */
251 sizeof(ModestMsgViewWindow),
253 (GInstanceInitFunc) modest_msg_view_window_init,
256 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
257 "ModestMsgViewWindow",
260 static const GInterfaceInfo modest_header_view_observer_info =
262 (GInterfaceInitFunc) modest_header_view_observer_init,
263 NULL, /* interface_finalize */
264 NULL /* interface_data */
267 g_type_add_interface_static (my_type,
268 MODEST_TYPE_HEADER_VIEW_OBSERVER,
269 &modest_header_view_observer_info);
275 save_state (ModestWindow *self)
277 modest_widget_memory_save (modest_runtime_get_conf (),
279 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
284 restore_settings (ModestMsgViewWindow *self)
287 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
290 conf = modest_runtime_get_conf ();
291 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
292 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
293 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
294 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
295 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
296 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
297 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
298 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
299 modest_widget_memory_restore (conf,
301 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
305 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
307 GObjectClass *gobject_class;
308 ModestWindowClass *modest_window_class;
309 gobject_class = (GObjectClass*) klass;
310 modest_window_class = (ModestWindowClass *) klass;
312 parent_class = g_type_class_peek_parent (klass);
313 gobject_class->finalize = modest_msg_view_window_finalize;
315 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
316 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
317 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
318 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
319 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
320 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
322 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
324 modest_window_class->save_state_func = save_state;
326 signals[MSG_CHANGED_SIGNAL] =
327 g_signal_new ("msg-changed",
328 G_TYPE_FROM_CLASS (gobject_class),
330 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
332 modest_marshal_VOID__POINTER_POINTER,
333 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
336 static void modest_header_view_observer_init(
337 ModestHeaderViewObserverIface *iface_class)
339 iface_class->update_func = modest_msg_view_window_update_model_replaced;
343 modest_msg_view_window_init (ModestMsgViewWindow *obj)
345 ModestMsgViewWindowPrivate *priv;
346 ModestWindowPrivate *parent_priv = NULL;
347 GtkActionGroup *action_group = NULL;
348 GError *error = NULL;
349 GdkPixbuf *window_icon;
351 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
352 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
353 parent_priv->ui_manager = gtk_ui_manager_new();
355 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
356 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
358 /* Add common actions */
359 gtk_action_group_add_actions (action_group,
360 modest_action_entries,
361 G_N_ELEMENTS (modest_action_entries),
363 gtk_action_group_add_toggle_actions (action_group,
364 modest_toggle_action_entries,
365 G_N_ELEMENTS (modest_toggle_action_entries),
367 gtk_action_group_add_toggle_actions (action_group,
368 msg_view_toggle_action_entries,
369 G_N_ELEMENTS (msg_view_toggle_action_entries),
371 gtk_action_group_add_radio_actions (action_group,
372 msg_view_zoom_action_entries,
373 G_N_ELEMENTS (msg_view_zoom_action_entries),
375 G_CALLBACK (modest_ui_actions_on_change_zoom),
378 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
379 g_object_unref (action_group);
381 /* Load the UI definition */
382 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
385 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
386 g_error_free (error);
391 /* Add accelerators */
392 gtk_window_add_accel_group (GTK_WINDOW (obj),
393 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
395 priv->is_search_result = FALSE;
397 priv->msg_view = NULL;
398 priv->header_model = NULL;
399 priv->header_folder_id = NULL;
400 priv->clipboard_change_handler = 0;
401 priv->queue_change_handler = 0;
402 priv->account_removed_handler = 0;
403 priv->row_changed_handler = 0;
404 priv->row_deleted_handler = 0;
405 priv->row_inserted_handler = 0;
406 priv->rows_reordered_handler = 0;
407 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
409 priv->optimized_view = FALSE;
410 priv->progress_bar_timeout = 0;
411 priv->purge_timeout = 0;
412 priv->remove_attachment_banner = NULL;
413 priv->msg_uid = NULL;
415 priv->sighandlers = NULL;
418 init_window (MODEST_MSG_VIEW_WINDOW(obj));
419 /* Set window icon */
420 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
422 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
423 g_object_unref (window_icon);
427 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
428 GTK_WINDOW(obj),"applications_email_viewer");
433 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
435 ModestMsgViewWindowPrivate *priv = NULL;
437 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
439 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
441 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
443 if (priv->progress_bar_timeout > 0) {
444 g_source_remove (priv->progress_bar_timeout);
445 priv->progress_bar_timeout = 0;
452 set_toolbar_mode (ModestMsgViewWindow *self,
453 ModestToolBarModes mode)
455 ModestWindowPrivate *parent_priv;
456 ModestMsgViewWindowPrivate *priv;
457 /* GtkWidget *widget = NULL; */
459 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
461 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
462 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
464 /* Sets current toolbar mode */
465 priv->current_toolbar_mode = mode;
467 /* Update toolbar dimming state */
468 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
471 case TOOLBAR_MODE_NORMAL:
472 if (priv->progress_toolitem) {
473 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
474 gtk_widget_hide (priv->progress_toolitem);
477 if (priv->progress_bar)
478 gtk_widget_hide (priv->progress_bar);
480 if (priv->cancel_toolitem)
481 gtk_widget_hide (priv->cancel_toolitem);
483 if (priv->prev_toolitem)
484 gtk_widget_show (priv->prev_toolitem);
486 if (priv->next_toolitem)
487 gtk_widget_show (priv->next_toolitem);
489 /* Hide toolbar if optimized view is enabled */
490 if (priv->optimized_view) {
491 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
492 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
496 case TOOLBAR_MODE_TRANSFER:
497 if (priv->prev_toolitem)
498 gtk_widget_hide (priv->prev_toolitem);
500 if (priv->next_toolitem)
501 gtk_widget_hide (priv->next_toolitem);
503 if (priv->progress_bar)
504 gtk_widget_show (priv->progress_bar);
506 if (priv->progress_toolitem) {
507 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
508 gtk_widget_show (priv->progress_toolitem);
511 if (priv->cancel_toolitem)
512 gtk_widget_show (priv->cancel_toolitem);
514 /* Show toolbar if it's hiden (optimized view ) */
515 if (priv->optimized_view) {
516 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
517 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
522 g_return_if_reached ();
529 menubar_to_menu (GtkUIManager *ui_manager)
531 GtkWidget *main_menu;
533 /* Get the menubar from the UI manager */
534 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
540 init_window (ModestMsgViewWindow *obj)
542 GtkWidget *main_vbox;
543 ModestMsgViewWindowPrivate *priv;
544 ModestWindowPrivate *parent_priv;
546 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
547 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
549 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
550 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
551 main_vbox = gtk_vbox_new (FALSE, 6);
553 #ifdef MODEST_USE_MOZEMBED
554 priv->main_scroll = priv->msg_view;
555 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
557 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
558 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
560 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
561 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
562 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
564 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
565 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
567 priv->find_toolbar = hildon_find_toolbar_new (NULL);
568 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
569 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
571 gtk_widget_show_all (GTK_WIDGET(main_vbox));
575 modest_msg_view_window_disconnect_signals (ModestWindow *self)
577 ModestMsgViewWindowPrivate *priv;
578 ModestHeaderView *header_view = NULL;
579 ModestWindow *main_window = NULL;
581 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
583 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
584 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
585 priv->clipboard_change_handler))
586 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
587 priv->clipboard_change_handler);
589 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
590 priv->queue_change_handler))
591 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
592 priv->queue_change_handler);
594 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
595 priv->account_removed_handler))
596 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
597 priv->account_removed_handler);
599 if (priv->header_model) {
600 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
601 priv->row_changed_handler))
602 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
603 priv->row_changed_handler);
605 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
606 priv->row_deleted_handler))
607 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
608 priv->row_deleted_handler);
610 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
611 priv->row_inserted_handler))
612 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
613 priv->row_inserted_handler);
615 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
616 priv->rows_reordered_handler))
617 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
618 priv->rows_reordered_handler);
621 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
622 priv->sighandlers = NULL;
624 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
625 FALSE); /* don't create */
629 header_view = MODEST_HEADER_VIEW(
630 modest_main_window_get_child_widget(
631 MODEST_MAIN_WINDOW(main_window),
632 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
633 if (header_view == NULL)
636 modest_header_view_remove_observer(header_view,
637 MODEST_HEADER_VIEW_OBSERVER(self));
641 modest_msg_view_window_finalize (GObject *obj)
643 ModestMsgViewWindowPrivate *priv;
645 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
647 /* Sanity check: shouldn't be needed, the window mgr should
648 call this function before */
649 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
651 if (priv->header_model != NULL) {
652 g_object_unref (priv->header_model);
653 priv->header_model = NULL;
656 if (priv->progress_bar_timeout > 0) {
657 g_source_remove (priv->progress_bar_timeout);
658 priv->progress_bar_timeout = 0;
661 if (priv->remove_attachment_banner) {
662 gtk_widget_destroy (priv->remove_attachment_banner);
663 g_object_unref (priv->remove_attachment_banner);
664 priv->remove_attachment_banner = NULL;
667 if (priv->purge_timeout > 0) {
668 g_source_remove (priv->purge_timeout);
669 priv->purge_timeout = 0;
672 if (priv->row_reference) {
673 gtk_tree_row_reference_free (priv->row_reference);
674 priv->row_reference = NULL;
677 if (priv->next_row_reference) {
678 gtk_tree_row_reference_free (priv->next_row_reference);
679 priv->next_row_reference = NULL;
683 g_free (priv->msg_uid);
684 priv->msg_uid = NULL;
687 G_OBJECT_CLASS(parent_class)->finalize (obj);
691 select_next_valid_row (GtkTreeModel *model,
692 GtkTreeRowReference **row_reference,
695 GtkTreeIter tmp_iter;
696 GtkTreePath *path, *next;
697 gboolean retval = FALSE;
699 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
701 path = gtk_tree_row_reference_get_path (*row_reference);
702 gtk_tree_model_get_iter (model, &tmp_iter, path);
703 gtk_tree_row_reference_free (*row_reference);
704 *row_reference = NULL;
706 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
707 next = gtk_tree_model_get_path (model, &tmp_iter);
708 *row_reference = gtk_tree_row_reference_new (model, next);
710 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
711 next = gtk_tree_model_get_path (model, &tmp_iter);
713 /* Ensure that we are not selecting the same */
714 if (gtk_tree_path_compare (path, next) != 0) {
715 *row_reference = gtk_tree_row_reference_new (model, next);
721 gtk_tree_path_free (path);
726 /* TODO: This should be in _init(), with the parameters as properties. */
728 modest_msg_view_window_construct (ModestMsgViewWindow *self,
729 const gchar *modest_account_name,
730 const gchar *msg_uid)
733 ModestMsgViewWindowPrivate *priv = NULL;
734 ModestWindowPrivate *parent_priv = NULL;
735 ModestDimmingRulesGroup *menu_rules_group = NULL;
736 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
737 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
739 obj = G_OBJECT (self);
740 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
741 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
743 priv->msg_uid = g_strdup (msg_uid);
746 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
747 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
748 gtk_widget_show (parent_priv->menubar);
749 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
751 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
752 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
753 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
755 /* Add common dimming rules */
756 modest_dimming_rules_group_add_rules (menu_rules_group,
757 modest_msg_view_menu_dimming_entries,
758 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
759 MODEST_WINDOW (self));
760 modest_dimming_rules_group_add_rules (toolbar_rules_group,
761 modest_msg_view_toolbar_dimming_entries,
762 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
763 MODEST_WINDOW (self));
764 modest_dimming_rules_group_add_rules (clipboard_rules_group,
765 modest_msg_view_clipboard_dimming_entries,
766 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
767 MODEST_WINDOW (self));
769 /* Insert dimming rules group for this window */
770 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
771 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
772 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
773 g_object_unref (menu_rules_group);
774 g_object_unref (toolbar_rules_group);
775 g_object_unref (clipboard_rules_group);
777 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
779 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
781 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);
782 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
783 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
784 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
785 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
786 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
787 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
788 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
789 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
790 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
791 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
793 g_signal_connect (G_OBJECT (obj), "key-release-event",
794 G_CALLBACK (modest_msg_view_window_key_event),
797 g_signal_connect (G_OBJECT (obj), "key-press-event",
798 G_CALLBACK (modest_msg_view_window_key_event),
801 g_signal_connect (G_OBJECT (obj), "window-state-event",
802 G_CALLBACK (modest_msg_view_window_window_state_event),
805 g_signal_connect (G_OBJECT (obj), "move-focus",
806 G_CALLBACK (on_move_focus), obj);
808 /* Mail Operation Queue */
809 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
811 G_CALLBACK (on_queue_changed),
814 /* Account manager */
815 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
817 G_CALLBACK(on_account_removed),
820 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
822 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
823 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
824 priv->last_search = NULL;
826 /* Init the clipboard actions dim status */
827 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
829 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
831 /* Check toolbar dimming rules */
832 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
833 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
837 /* FIXME: parameter checks */
839 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
840 const gchar *modest_account_name,
841 const gchar *msg_uid,
843 GtkTreeRowReference *row_reference)
845 ModestMsgViewWindow *window = NULL;
846 ModestMsgViewWindowPrivate *priv = NULL;
847 TnyFolder *header_folder = NULL;
848 ModestHeaderView *header_view = NULL;
849 ModestWindow *main_window = NULL;
850 ModestWindowMgr *mgr = NULL;
852 mgr = modest_runtime_get_window_mgr ();
853 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
854 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
856 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
858 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
860 /* Remember the message list's TreeModel so we can detect changes
861 * and change the list selection when necessary: */
863 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
865 g_warning ("%s: BUG: no main window", __FUNCTION__);
869 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
870 MODEST_MAIN_WINDOW(main_window),
871 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
872 if (header_view != NULL){
873 header_folder = modest_header_view_get_folder(header_view);
874 g_assert(header_folder != NULL);
875 priv->header_folder_id = tny_folder_get_id(header_folder);
876 g_assert(priv->header_folder_id != NULL);
877 g_object_unref(header_folder);
880 priv->header_model = g_object_ref(model);
881 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
882 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
883 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
885 priv->row_changed_handler = g_signal_connect(
886 GTK_TREE_MODEL(model), "row-changed",
887 G_CALLBACK(modest_msg_view_window_on_row_changed),
889 priv->row_deleted_handler = g_signal_connect(
890 GTK_TREE_MODEL(model), "row-deleted",
891 G_CALLBACK(modest_msg_view_window_on_row_deleted),
893 priv->row_inserted_handler = g_signal_connect (
894 GTK_TREE_MODEL(model), "row-inserted",
895 G_CALLBACK(modest_msg_view_window_on_row_inserted),
897 priv->rows_reordered_handler = g_signal_connect(
898 GTK_TREE_MODEL(model), "rows-reordered",
899 G_CALLBACK(modest_msg_view_window_on_row_reordered),
902 if (header_view != NULL){
903 modest_header_view_add_observer(header_view,
904 MODEST_HEADER_VIEW_OBSERVER(window));
907 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
908 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
909 gtk_widget_show_all (GTK_WIDGET (window));
911 modest_msg_view_window_update_priority (window);
913 /* Check toolbar dimming rules */
914 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
916 return MODEST_WINDOW(window);
920 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
921 const gchar *modest_account_name,
922 const gchar *msg_uid)
924 ModestMsgViewWindow *window = NULL;
925 ModestMsgViewWindowPrivate *priv = NULL;
926 ModestWindowMgr *mgr = NULL;
928 mgr = modest_runtime_get_window_mgr ();
929 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
930 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
931 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
933 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
935 /* Remember that this is a search result,
936 * so we can disable some UI appropriately: */
937 priv->is_search_result = TRUE;
939 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
940 update_window_title (window);
942 return MODEST_WINDOW(window);
946 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
947 const gchar *modest_account_name,
948 const gchar *msg_uid)
951 ModestMsgViewWindowPrivate *priv;
952 ModestWindowMgr *mgr = NULL;
954 g_return_val_if_fail (msg, NULL);
955 mgr = modest_runtime_get_window_mgr ();
956 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
957 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
958 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
959 modest_account_name, msg_uid);
961 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
962 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
964 return MODEST_WINDOW(obj);
967 void modest_msg_view_window_on_row_changed(
968 GtkTreeModel *header_model,
971 ModestMsgViewWindow *window){
972 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
975 void modest_msg_view_window_on_row_deleted(
976 GtkTreeModel *header_model,
978 ModestMsgViewWindow *window){
979 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
982 /* On insertions we check if the folder still has the message we are
983 * showing or do not. If do not, we do nothing. Which means we are still
984 * not attached to any header folder and thus next/prev buttons are
985 * still dimmed. Once the message that is shown by msg-view is found, the
986 * new model of header-view will be attached and the references will be set.
987 * On each further insertions dimming rules will be checked. However
988 * this requires extra CPU time at least works.
989 * (An message might be deleted from TnyFolder and thus will not be
990 * inserted into the model again for example if it is removed by the
991 * imap server and the header view is refreshed.)
993 void modest_msg_view_window_on_row_inserted(
994 GtkTreeModel *new_model,
995 GtkTreePath *tree_path,
996 GtkTreeIter *tree_iter,
997 ModestMsgViewWindow *window){
998 ModestMsgViewWindowPrivate *priv = NULL;
999 TnyHeader *header = NULL;
1002 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1004 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1006 /* If we already has a model attached then the message shown by
1007 * msg-view is in it, and thus we do not need any actions but
1008 * to check the dimming rules.*/
1009 if(priv->header_model != NULL){
1010 gtk_tree_row_reference_free(priv->next_row_reference);
1011 priv->next_row_reference = gtk_tree_row_reference_copy(
1012 priv->row_reference);
1013 select_next_valid_row (priv->header_model,
1014 &(priv->next_row_reference), FALSE);
1015 modest_ui_actions_check_toolbar_dimming_rules (
1016 MODEST_WINDOW (window));
1020 /* Check if the newly inserted message is the same we are actually
1021 * showing. IF not, we should remain detached from the header model
1022 * and thus prev and next toolbarbuttons should remain dimmed. */
1023 gtk_tree_model_get (new_model, tree_iter,
1024 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1025 uid = modest_tny_folder_get_header_unique_id(header);
1026 g_object_unref(G_OBJECT(header));
1028 if(!g_str_equal(priv->msg_uid, uid)){
1034 /* Setup row_reference for the actual msg. */
1035 priv->row_reference = gtk_tree_row_reference_new(
1036 new_model, tree_path);
1037 if(priv->row_reference == NULL){
1038 g_warning("No reference for msg header item.");
1042 /* Attach new_model and connect some callback to it to become able
1043 * to detect changes in header-view. */
1044 priv->header_model = g_object_ref(new_model);
1045 g_signal_connect (new_model, "row-changed",
1046 G_CALLBACK (modest_msg_view_window_on_row_changed),
1048 g_signal_connect (new_model, "row-deleted",
1049 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1051 g_signal_connect (new_model, "rows-reordered",
1052 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1055 /* Now set up next_row_reference. */
1056 priv->next_row_reference = gtk_tree_row_reference_copy(
1057 priv->row_reference);
1058 select_next_valid_row (priv->header_model,
1059 &(priv->next_row_reference), FALSE);
1061 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1064 void modest_msg_view_window_on_row_reordered(
1065 GtkTreeModel *header_model,
1069 ModestMsgViewWindow *window){
1070 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1073 /* The modest_msg_view_window_update_model_replaced implements update
1074 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1075 * actually belongs to the header-view is the same as the TnyFolder of
1076 * the message of msg-view or not. If they are different, there is
1077 * nothing to do. If they are the same, then the model has replaced and
1078 * the reference in msg-view shall be replaced from the old model to
1079 * the new model. In this case the view will be detached from it's
1080 * header folder. From this point the next/prev buttons are dimmed.
1082 void modest_msg_view_window_update_model_replaced(
1083 ModestHeaderViewObserver *observer,
1084 GtkTreeModel *model,
1085 const gchar *tny_folder_id){
1086 ModestMsgViewWindowPrivate *priv = NULL;
1087 ModestMsgViewWindow *window = NULL;
1089 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1090 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1092 window = MODEST_MSG_VIEW_WINDOW(observer);
1093 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1095 /* If there is an other folder in the header-view then we do
1096 * not care about it's model (msg list). Else if the
1097 * header-view shows the folder the msg shown by us is in, we
1098 * shall replace our model reference and make some check. */
1099 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1102 /* Model is changed(replaced), so we should forget the old
1103 * one. Because there might be other references and there
1104 * might be some change on the model even if we unreferenced
1105 * it, we need to disconnect our signals here. */
1106 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1107 priv->row_changed_handler))
1108 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1109 priv->row_changed_handler);
1110 priv->row_changed_handler = 0;
1111 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1112 priv->row_deleted_handler))
1113 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1114 priv->row_deleted_handler);
1115 priv->row_deleted_handler = 0;
1116 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1117 priv->row_inserted_handler))
1118 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1119 priv->row_inserted_handler);
1120 priv->row_inserted_handler = 0;
1121 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1122 priv->rows_reordered_handler))
1123 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1124 priv->rows_reordered_handler);
1125 priv->rows_reordered_handler = 0;
1126 g_object_unref(priv->header_model);
1127 priv->header_model = NULL;
1128 g_object_unref(priv->row_reference);
1129 priv->row_reference = NULL;
1130 g_object_unref(priv->next_row_reference);
1131 priv->next_row_reference = NULL;
1133 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1135 g_assert(model != NULL);
1137 /* Also we must connect to the new model for row insertions.
1138 * Only for insertions now. We will need other ones only after
1139 * the msg is show by msg-view is added to the new model. */
1140 priv->row_inserted_handler = g_signal_connect (
1141 model, "row-inserted",
1142 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1147 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1149 ModestMsgViewWindowPrivate *priv= NULL;
1151 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1152 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1154 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1158 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1160 ModestMsgViewWindowPrivate *priv= NULL;
1162 TnyHeader *header = NULL;
1163 GtkTreePath *path = NULL;
1166 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1167 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1169 /* If the message was not obtained from a treemodel,
1170 * for instance if it was opened directly by the search UI:
1172 if (priv->header_model == NULL) {
1173 msg = modest_msg_view_window_get_message (self);
1175 header = tny_msg_get_header (msg);
1176 g_object_unref (msg);
1181 /* Get iter of the currently selected message in the header view: */
1182 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1183 * instead of sometimes retrieving it from the header view?
1184 * Then we wouldn't be dependent on the message actually still being selected
1185 * in the header view. murrayc. */
1186 if (!gtk_tree_row_reference_valid (priv->row_reference))
1188 path = gtk_tree_row_reference_get_path (priv->row_reference);
1189 g_return_val_if_fail (path != NULL, NULL);
1190 gtk_tree_model_get_iter (priv->header_model,
1194 /* Get current message header */
1195 gtk_tree_model_get (priv->header_model, &iter,
1196 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1199 gtk_tree_path_free (path);
1204 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1206 ModestMsgViewWindowPrivate *priv;
1208 g_return_val_if_fail (self, NULL);
1210 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1212 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1216 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1218 ModestMsgViewWindowPrivate *priv;
1220 g_return_val_if_fail (self, NULL);
1222 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1224 return (const gchar*) priv->msg_uid;
1228 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1231 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1232 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1233 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1237 is_active = gtk_toggle_action_get_active (toggle);
1240 gtk_widget_show (priv->find_toolbar);
1241 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1243 gtk_widget_hide (priv->find_toolbar);
1246 /* update the toggle buttons status */
1247 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1248 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1249 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1250 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1255 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1256 ModestMsgViewWindow *obj)
1258 GtkToggleAction *toggle;
1259 ModestWindowPrivate *parent_priv;
1260 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1262 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1263 gtk_toggle_action_set_active (toggle, FALSE);
1267 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1268 ModestMsgViewWindow *obj)
1270 gchar *current_search;
1271 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1273 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1274 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1278 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1280 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1281 g_free (current_search);
1282 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1286 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1288 g_free (priv->last_search);
1289 priv->last_search = g_strdup (current_search);
1290 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1293 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1294 g_free (priv->last_search);
1295 priv->last_search = NULL;
1297 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1300 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1301 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1302 g_free (priv->last_search);
1303 priv->last_search = NULL;
1305 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1309 g_free (current_search);
1314 modest_msg_view_window_set_zoom (ModestWindow *window,
1317 ModestMsgViewWindowPrivate *priv;
1318 ModestWindowPrivate *parent_priv;
1319 GtkAction *action = NULL;
1320 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1322 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1324 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1325 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1326 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1328 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1329 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1331 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1335 modest_msg_view_window_get_zoom (ModestWindow *window)
1337 ModestMsgViewWindowPrivate *priv;
1339 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1341 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1342 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1346 modest_msg_view_window_zoom_plus (ModestWindow *window)
1348 ModestWindowPrivate *parent_priv;
1349 GtkRadioAction *zoom_radio_action;
1350 GSList *group, *node;
1352 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1353 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1354 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1356 group = gtk_radio_action_get_group (zoom_radio_action);
1358 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1359 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1363 for (node = group; node != NULL; node = g_slist_next (node)) {
1364 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1365 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1373 modest_msg_view_window_zoom_minus (ModestWindow *window)
1375 ModestWindowPrivate *parent_priv;
1376 GtkRadioAction *zoom_radio_action;
1377 GSList *group, *node;
1379 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1380 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1381 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1383 group = gtk_radio_action_get_group (zoom_radio_action);
1385 for (node = group; node != NULL; node = g_slist_next (node)) {
1386 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1387 if (node->next != NULL) {
1388 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1391 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1401 modest_msg_view_window_key_event (GtkWidget *window,
1406 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1407 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1408 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1409 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1410 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1411 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1412 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1413 gboolean return_value;
1415 if (event->type == GDK_KEY_RELEASE) {
1416 GtkScrollType scroll_type;
1418 switch (event->keyval) {
1421 scroll_type = GTK_SCROLL_STEP_UP; break;
1424 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1426 case GDK_KP_Page_Up:
1427 scroll_type = GTK_SCROLL_PAGE_UP; break;
1429 case GDK_KP_Page_Down:
1430 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1433 scroll_type = GTK_SCROLL_START; break;
1436 scroll_type = GTK_SCROLL_END; break;
1437 default: scroll_type = GTK_SCROLL_NONE;
1440 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1441 scroll_type, FALSE, &return_value);
1452 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1455 ModestMsgViewWindowPrivate *priv;
1456 GtkTreeIter tmp_iter;
1457 gboolean is_last_selected;
1459 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1460 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1462 /*if no model (so no rows at all), then virtually we are the last*/
1463 if (!priv->header_model)
1466 path = gtk_tree_row_reference_get_path (priv->row_reference);
1470 is_last_selected = TRUE;
1471 while (is_last_selected) {
1473 gtk_tree_path_next (path);
1474 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1476 gtk_tree_model_get (priv->header_model, &tmp_iter,
1477 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1480 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1481 is_last_selected = FALSE;
1482 g_object_unref(G_OBJECT(header));
1485 gtk_tree_path_free (path);
1486 return is_last_selected;
1490 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1492 ModestMsgViewWindowPrivate *priv;
1494 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1495 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1497 return priv->header_model != NULL;
1501 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1503 ModestMsgViewWindowPrivate *priv;
1505 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1506 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1508 return priv->is_search_result;
1512 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1515 ModestMsgViewWindowPrivate *priv;
1516 gboolean is_first_selected;
1517 GtkTreeIter tmp_iter;
1518 /* gchar * path_string;*/
1520 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1521 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1523 /*if no model (so no rows at all), then virtually we are the first*/
1524 if (!priv->header_model)
1527 path = gtk_tree_row_reference_get_path (priv->row_reference);
1531 /* path_string = gtk_tree_path_to_string (path);
1532 is_first_selected = strcmp (path_string, "0");
1534 g_free (path_string);
1535 gtk_tree_path_free (path);
1537 return is_first_selected;*/
1539 is_first_selected = TRUE;
1540 while (is_first_selected) {
1542 if(!gtk_tree_path_prev (path))
1544 /* Here the 'if' is needless for logic, but let make sure
1545 * iter is valid for gtk_tree_model_get. */
1546 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1548 gtk_tree_model_get (priv->header_model, &tmp_iter,
1549 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1552 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1553 is_first_selected = FALSE;
1554 g_object_unref(G_OBJECT(header));
1557 gtk_tree_path_free (path);
1558 return is_first_selected;
1562 * Reads the message whose summary item is @header. It takes care of
1563 * several things, among others:
1565 * If the message was not previously downloaded then ask the user
1566 * before downloading. If there is no connection launch the connection
1567 * dialog. Update toolbar dimming rules.
1569 * Returns: TRUE if the mail operation was started, otherwise if the
1570 * user do not want to download the message, or if the user do not
1571 * want to connect, then the operation is not issued
1574 message_reader (ModestMsgViewWindow *window,
1575 ModestMsgViewWindowPrivate *priv,
1577 GtkTreeRowReference *row_reference)
1579 ModestMailOperation *mail_op = NULL;
1580 gboolean already_showing = FALSE;
1581 ModestWindow *msg_window = NULL;
1582 ModestWindowMgr *mgr;
1584 g_return_val_if_fail (row_reference != NULL, FALSE);
1586 mgr = modest_runtime_get_window_mgr ();
1587 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1588 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1591 gtk_window_present (GTK_WINDOW (msg_window));
1592 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1596 /* Msg download completed */
1597 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
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));
1984 /* Set reply button tap and hold menu */
1985 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1986 "/ToolBar/ToolbarMessageReply");
1987 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1988 "/ToolbarReplyCSM");
1989 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1993 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1994 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1995 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1997 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1998 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
1999 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2001 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2004 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2005 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2008 /* Update also the actions (to update the toggles in the
2009 menus), we have to do it manually because some other window
2010 of the same time could have changed it (remember that the
2011 toolbar fullscreen mode is shared by all the windows of the
2013 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2014 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2016 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2018 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2019 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2024 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2026 ModestMsgViewWindow *window)
2028 if (!GTK_WIDGET_VISIBLE (window))
2031 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2035 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2037 ModestMsgViewWindowPrivate *priv;
2039 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2040 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2042 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2046 cancel_progressbar (GtkToolButton *toolbutton,
2047 ModestMsgViewWindow *self)
2050 ModestMsgViewWindowPrivate *priv;
2052 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2054 /* Get operation observers and cancel its current operation */
2055 tmp = priv->progress_widgets;
2057 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2058 tmp=g_slist_next(tmp);
2062 observers_empty (ModestMsgViewWindow *self)
2065 ModestMsgViewWindowPrivate *priv;
2066 gboolean is_empty = TRUE;
2067 guint pending_ops = 0;
2069 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2070 tmp = priv->progress_widgets;
2072 /* Check all observers */
2073 while (tmp && is_empty) {
2074 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2075 is_empty = pending_ops == 0;
2077 tmp = g_slist_next(tmp);
2084 on_account_removed (TnyAccountStore *account_store,
2085 TnyAccount *account,
2088 /* Do nothing if it's a transport account, because we only
2089 show the messages of a store account */
2090 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2091 const gchar *parent_acc = NULL;
2092 const gchar *our_acc = NULL;
2094 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2095 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2097 /* Close this window if I'm showing a message of the removed account */
2098 if (strcmp (parent_acc, our_acc) == 0)
2099 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2104 on_mail_operation_started (ModestMailOperation *mail_op,
2107 ModestMsgViewWindow *self;
2108 ModestMailOperationTypeOperation op_type;
2110 ModestMsgViewWindowPrivate *priv;
2112 self = MODEST_MSG_VIEW_WINDOW (user_data);
2113 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2114 op_type = modest_mail_operation_get_type_operation (mail_op);
2115 tmp = priv->progress_widgets;
2117 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2118 set_toolbar_transfer_mode(self);
2120 modest_progress_object_add_operation (
2121 MODEST_PROGRESS_OBJECT (tmp->data),
2123 tmp = g_slist_next (tmp);
2129 on_mail_operation_finished (ModestMailOperation *mail_op,
2132 ModestMsgViewWindow *self;
2133 ModestMailOperationTypeOperation op_type;
2135 ModestMsgViewWindowPrivate *priv;
2137 self = MODEST_MSG_VIEW_WINDOW (user_data);
2138 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2139 op_type = modest_mail_operation_get_type_operation (mail_op);
2140 tmp = priv->progress_widgets;
2142 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2144 modest_progress_object_remove_operation (
2145 MODEST_PROGRESS_OBJECT (tmp->data),
2147 tmp = g_slist_next (tmp);
2150 /* If no more operations are being observed, NORMAL mode is enabled again */
2151 if (observers_empty (self)) {
2152 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2158 on_queue_changed (ModestMailOperationQueue *queue,
2159 ModestMailOperation *mail_op,
2160 ModestMailOperationQueueNotification type,
2161 ModestMsgViewWindow *self)
2163 ModestMsgViewWindowPrivate *priv;
2165 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2167 /* If this operations was created by another window, do nothing */
2168 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2171 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2172 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2174 "operation-started",
2175 G_CALLBACK (on_mail_operation_started),
2177 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2179 "operation-finished",
2180 G_CALLBACK (on_mail_operation_finished),
2182 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2183 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2185 "operation-started");
2186 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2188 "operation-finished");
2193 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2195 ModestMsgViewWindowPrivate *priv;
2196 GList *selected_attachments = NULL;
2198 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2199 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2201 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2203 return selected_attachments;
2207 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2209 ModestMsgViewWindowPrivate *priv;
2210 const gchar *msg_uid;
2211 gchar *attachment_uid = NULL;
2212 gint attachment_index = 0;
2215 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2216 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2217 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2219 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2220 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2221 attachment_index = g_list_index (attachments, mime_part);
2222 g_list_free (attachments);
2224 if (msg_uid && attachment_index >= 0) {
2225 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2228 if (mime_part == NULL) {
2229 gboolean error = FALSE;
2230 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2231 if (selected_attachments == NULL) {
2233 } else if (g_list_length (selected_attachments) > 1) {
2234 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2237 mime_part = (TnyMimePart *) selected_attachments->data;
2238 g_object_ref (mime_part);
2240 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2241 g_list_free (selected_attachments);
2246 g_object_ref (mime_part);
2249 if (tny_mime_part_is_purged (mime_part)) {
2250 g_object_unref (mime_part);
2254 if (!TNY_IS_MSG (mime_part)) {
2255 gchar *filepath = NULL;
2256 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2257 const gchar *content_type;
2258 TnyFsStream *temp_stream = NULL;
2259 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2262 if (temp_stream != NULL) {
2263 content_type = tny_mime_part_get_content_type (mime_part);
2264 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2266 /* make the file read-only */
2267 if (g_chmod(filepath, 0444) != 0)
2268 g_warning ("%s: failed to set file '%s' to read-only: %s",
2269 __FUNCTION__, filepath, strerror(errno));
2271 modest_platform_activate_file (filepath, content_type);
2272 g_object_unref (temp_stream);
2274 /* NOTE: files in the temporary area will be automatically
2275 * cleaned after some time if they are no longer in use */
2276 } else if (filepath != NULL) {
2277 /* the file may already exist but it isn't writable,
2278 * let's try to open it anyway */
2279 content_type = tny_mime_part_get_content_type (mime_part);
2280 modest_platform_activate_file (filepath, content_type);
2284 /* message attachment */
2285 TnyHeader *header = NULL;
2286 ModestWindowMgr *mgr;
2287 ModestWindow *msg_win = NULL;
2290 header = tny_msg_get_header (TNY_MSG (mime_part));
2291 mgr = modest_runtime_get_window_mgr ();
2292 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2295 if (msg_win) /* there is already a window for this uid; top it */
2296 gtk_window_present (GTK_WINDOW(msg_win));
2298 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2299 * thus, we don't do anything */
2300 g_warning ("window for is already being created");
2302 /* it's not found, so create a new window for it */
2303 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2304 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2306 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2307 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2308 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2309 modest_window_get_zoom (MODEST_WINDOW (window)));
2310 modest_window_mgr_register_window (mgr, msg_win);
2311 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2312 gtk_widget_show_all (GTK_WIDGET (msg_win));
2315 g_object_unref (mime_part);
2331 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2332 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2333 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2334 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2337 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2341 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2342 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2343 g_free (pair->filename);
2344 g_object_unref (pair->part);
2345 g_slice_free (SaveMimePartPair, pair);
2347 g_list_free (info->pairs);
2350 gtk_widget_destroy (info->banner);
2351 g_object_unref (info->banner);
2352 g_slice_free (SaveMimePartInfo, info);
2357 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2359 if (info->pairs != NULL) {
2360 save_mime_part_to_file (info);
2363 result = info->result;
2365 /* This is a GDK lock because we are an idle callback and
2366 * hildon_banner_show_information is or does Gtk+ code */
2368 gdk_threads_enter (); /* CHECKED */
2369 save_mime_part_info_free (info, TRUE);
2371 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2373 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2375 gdk_threads_leave (); /* CHECKED */
2382 save_mime_part_to_file (SaveMimePartInfo *info)
2384 GnomeVFSResult result;
2385 GnomeVFSHandle *handle;
2387 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2389 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2390 if (result == GNOME_VFS_OK) {
2391 stream = tny_vfs_stream_new (handle);
2392 tny_mime_part_decode_to_stream (pair->part, stream);
2393 g_object_unref (G_OBJECT (stream));
2394 g_object_unref (pair->part);
2395 g_slice_free (SaveMimePartPair, pair);
2396 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2397 info->result = TRUE;
2399 save_mime_part_info_free (info, FALSE);
2400 info->result = FALSE;
2403 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2408 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2410 gboolean is_ok = TRUE;
2411 gint replaced_files = 0;
2412 const GList *files = info->pairs;
2415 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2416 SaveMimePartPair *pair = iter->data;
2417 if (modest_utils_file_exists (pair->filename)) {
2421 if (replaced_files) {
2422 GtkWidget *confirm_overwrite_dialog;
2423 const gchar *message = (replaced_files == 1) ?
2424 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2425 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2426 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2429 gtk_widget_destroy (confirm_overwrite_dialog);
2433 save_mime_part_info_free (info, TRUE);
2435 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2436 _CS("sfil_ib_saving"));
2437 info->banner = g_object_ref (banner);
2438 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2439 g_object_unref (banner);
2446 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2448 gboolean clean_list = FALSE;
2449 ModestMsgViewWindowPrivate *priv;
2450 GList *files_to_save = NULL;
2451 GtkWidget *save_dialog = NULL;
2452 gchar *folder = NULL;
2453 gboolean canceled = FALSE;
2454 const gchar *filename = NULL;
2455 gchar *save_multiple_str = NULL;
2457 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2458 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2460 if (mime_parts == NULL) {
2461 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2462 if (mime_parts == NULL)
2467 /* prepare dialog */
2468 if (mime_parts->next == NULL) {
2469 /* only one attachment selected */
2470 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2471 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2472 filename = tny_mime_part_get_filename (mime_part);
2474 g_warning ("Tried to save a non-file attachment");
2478 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2479 g_list_length (mime_parts));
2482 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2483 GTK_FILE_CHOOSER_ACTION_SAVE);
2486 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2487 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2491 if (filename != NULL)
2492 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2495 /* if multiple, set multiple string */
2496 if (save_multiple_str) {
2497 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2501 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2502 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2504 if (!modest_utils_folder_writable (chooser_uri)) {
2505 hildon_banner_show_information
2506 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2510 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2511 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2513 if (tny_mime_part_is_attachment (mime_part)) {
2514 SaveMimePartPair *pair;
2516 if ((mime_parts->next != NULL) &&
2517 (tny_mime_part_get_filename (mime_part) == NULL))
2520 pair = g_slice_new0 (SaveMimePartPair);
2521 if (mime_parts->next == NULL) {
2522 pair->filename = g_strdup (chooser_uri);
2525 g_build_filename (chooser_uri,
2526 tny_mime_part_get_filename (mime_part), NULL);
2528 pair->part = g_object_ref (mime_part);
2529 files_to_save = g_list_prepend (files_to_save, pair);
2533 g_free (chooser_uri);
2536 gtk_widget_destroy (save_dialog);
2539 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2540 g_list_free (mime_parts);
2543 if (files_to_save != NULL) {
2544 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2545 info->pairs = files_to_save;
2546 info->result = TRUE;
2547 save_mime_parts_to_file_with_checks (info);
2552 show_remove_attachment_information (gpointer userdata)
2554 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2555 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2557 /* We're outside the main lock */
2558 gdk_threads_enter ();
2560 if (priv->remove_attachment_banner != NULL) {
2561 gtk_widget_destroy (priv->remove_attachment_banner);
2562 g_object_unref (priv->remove_attachment_banner);
2565 priv->remove_attachment_banner = g_object_ref (
2566 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2568 gdk_threads_leave ();
2574 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2576 ModestMsgViewWindowPrivate *priv;
2577 GList *mime_parts = NULL, *node;
2578 gchar *confirmation_message;
2582 /* TnyFolder *folder; */
2584 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2585 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2588 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2590 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2592 /* Remove already purged messages from mime parts list */
2594 while (node != NULL) {
2595 TnyMimePart *part = TNY_MIME_PART (node->data);
2596 if (tny_mime_part_is_purged (part)) {
2597 GList *deleted_node = node;
2598 node = g_list_next (node);
2599 g_object_unref (part);
2600 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2602 node = g_list_next (node);
2606 if (mime_parts == NULL)
2609 n_attachments = g_list_length (mime_parts);
2610 if (n_attachments == 1) {
2611 const gchar *filename;
2613 if (TNY_IS_MSG (mime_parts->data)) {
2615 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2616 filename = tny_header_get_subject (header);
2617 g_object_unref (header);
2618 if (filename == NULL)
2619 filename = _("mail_va_no_subject");
2621 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2623 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2625 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2626 "mcen_nc_purge_files_text",
2627 n_attachments), n_attachments);
2629 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2630 confirmation_message);
2631 g_free (confirmation_message);
2633 if (response != GTK_RESPONSE_OK)
2636 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2637 /* folder = tny_msg_get_folder (msg); */
2638 /* tny_msg_uncache_attachments (msg); */
2639 /* tny_folder_refresh (folder, NULL); */
2640 /* g_object_unref (folder); */
2642 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2643 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2644 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2647 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2648 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2649 tny_msg_rewrite_cache (msg);
2650 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2652 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2653 g_list_free (mime_parts);
2655 if (priv->purge_timeout > 0) {
2656 g_source_remove (priv->purge_timeout);
2657 priv->purge_timeout = 0;
2660 if (priv->remove_attachment_banner) {
2661 gtk_widget_destroy (priv->remove_attachment_banner);
2662 g_object_unref (priv->remove_attachment_banner);
2663 priv->remove_attachment_banner = NULL;
2671 update_window_title (ModestMsgViewWindow *window)
2673 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2675 TnyHeader *header = NULL;
2676 const gchar *subject = NULL;
2678 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2681 header = tny_msg_get_header (msg);
2682 subject = tny_header_get_subject (header);
2683 g_object_unref (msg);
2686 if ((subject == NULL)||(subject[0] == '\0'))
2687 subject = _("mail_va_no_subject");
2689 gtk_window_set_title (GTK_WINDOW (window), subject);
2693 static void on_move_focus (GtkWidget *widget,
2694 GtkDirectionType direction,
2697 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");