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);
157 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
160 /* list my signals */
166 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
167 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
168 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
171 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
172 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
173 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
174 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
175 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
176 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
177 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
180 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
181 struct _ModestMsgViewWindowPrivate {
184 GtkWidget *main_scroll;
185 GtkWidget *find_toolbar;
188 /* Progress observers */
189 GtkWidget *progress_bar;
190 GSList *progress_widgets;
193 GtkWidget *progress_toolitem;
194 GtkWidget *cancel_toolitem;
195 GtkWidget *prev_toolitem;
196 GtkWidget *next_toolitem;
197 ModestToolBarModes current_toolbar_mode;
199 /* Optimized view enabled */
200 gboolean optimized_view;
202 /* Whether this was created via the *_new_for_search_result() function. */
203 gboolean is_search_result;
205 /* Whether the message is in outbox */
208 /* A reference to the @model of the header view
209 * to allow selecting previous/next messages,
210 * if the message is currently selected in the header view.
212 const gchar *header_folder_id;
213 GtkTreeModel *header_model;
214 GtkTreeRowReference *row_reference;
215 GtkTreeRowReference *next_row_reference;
217 gulong clipboard_change_handler;
218 gulong queue_change_handler;
219 gulong account_removed_handler;
220 gulong row_changed_handler;
221 gulong row_deleted_handler;
222 gulong row_inserted_handler;
223 gulong rows_reordered_handler;
226 GtkWidget *remove_attachment_banner;
228 guint progress_bar_timeout;
235 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
236 MODEST_TYPE_MSG_VIEW_WINDOW, \
237 ModestMsgViewWindowPrivate))
239 static GtkWindowClass *parent_class = NULL;
241 /* uncomment the following if you have defined any signals */
242 static guint signals[LAST_SIGNAL] = {0};
245 modest_msg_view_window_get_type (void)
247 static GType my_type = 0;
249 static const GTypeInfo my_info = {
250 sizeof(ModestMsgViewWindowClass),
251 NULL, /* base init */
252 NULL, /* base finalize */
253 (GClassInitFunc) modest_msg_view_window_class_init,
254 NULL, /* class finalize */
255 NULL, /* class data */
256 sizeof(ModestMsgViewWindow),
258 (GInstanceInitFunc) modest_msg_view_window_init,
261 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
262 "ModestMsgViewWindow",
265 static const GInterfaceInfo modest_header_view_observer_info =
267 (GInterfaceInitFunc) modest_header_view_observer_init,
268 NULL, /* interface_finalize */
269 NULL /* interface_data */
272 g_type_add_interface_static (my_type,
273 MODEST_TYPE_HEADER_VIEW_OBSERVER,
274 &modest_header_view_observer_info);
280 save_state (ModestWindow *self)
282 modest_widget_memory_save (modest_runtime_get_conf (),
284 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
289 restore_settings (ModestMsgViewWindow *self)
292 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
295 conf = modest_runtime_get_conf ();
296 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
297 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
298 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
299 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
300 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
301 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
302 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
303 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
304 modest_widget_memory_restore (conf,
306 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
310 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
312 GObjectClass *gobject_class;
313 ModestWindowClass *modest_window_class;
314 gobject_class = (GObjectClass*) klass;
315 modest_window_class = (ModestWindowClass *) klass;
317 parent_class = g_type_class_peek_parent (klass);
318 gobject_class->finalize = modest_msg_view_window_finalize;
320 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
321 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
322 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
323 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
324 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
325 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
327 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
329 modest_window_class->save_state_func = save_state;
331 signals[MSG_CHANGED_SIGNAL] =
332 g_signal_new ("msg-changed",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
337 modest_marshal_VOID__POINTER_POINTER,
338 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
341 static void modest_header_view_observer_init(
342 ModestHeaderViewObserverIface *iface_class)
344 iface_class->update_func = modest_msg_view_window_update_model_replaced;
348 modest_msg_view_window_init (ModestMsgViewWindow *obj)
350 ModestMsgViewWindowPrivate *priv;
351 ModestWindowPrivate *parent_priv = NULL;
352 GtkActionGroup *action_group = NULL;
353 GError *error = NULL;
354 GdkPixbuf *window_icon;
356 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
357 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
358 parent_priv->ui_manager = gtk_ui_manager_new();
360 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
361 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
363 /* Add common actions */
364 gtk_action_group_add_actions (action_group,
365 modest_action_entries,
366 G_N_ELEMENTS (modest_action_entries),
368 gtk_action_group_add_toggle_actions (action_group,
369 modest_toggle_action_entries,
370 G_N_ELEMENTS (modest_toggle_action_entries),
372 gtk_action_group_add_toggle_actions (action_group,
373 msg_view_toggle_action_entries,
374 G_N_ELEMENTS (msg_view_toggle_action_entries),
376 gtk_action_group_add_radio_actions (action_group,
377 msg_view_zoom_action_entries,
378 G_N_ELEMENTS (msg_view_zoom_action_entries),
380 G_CALLBACK (modest_ui_actions_on_change_zoom),
383 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
384 g_object_unref (action_group);
386 /* Load the UI definition */
387 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
390 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
391 g_error_free (error);
396 /* Add accelerators */
397 gtk_window_add_accel_group (GTK_WINDOW (obj),
398 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
400 priv->is_search_result = FALSE;
401 priv->is_outbox = FALSE;
403 priv->msg_view = NULL;
404 priv->header_model = NULL;
405 priv->header_folder_id = NULL;
406 priv->clipboard_change_handler = 0;
407 priv->queue_change_handler = 0;
408 priv->account_removed_handler = 0;
409 priv->row_changed_handler = 0;
410 priv->row_deleted_handler = 0;
411 priv->row_inserted_handler = 0;
412 priv->rows_reordered_handler = 0;
413 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
415 priv->optimized_view = FALSE;
416 priv->progress_bar_timeout = 0;
417 priv->purge_timeout = 0;
418 priv->remove_attachment_banner = NULL;
419 priv->msg_uid = NULL;
421 priv->sighandlers = NULL;
424 init_window (MODEST_MSG_VIEW_WINDOW(obj));
426 /* Set window icon */
427 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
429 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
430 g_object_unref (window_icon);
433 hildon_program_add_window (hildon_program_get_instance(),
436 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
437 GTK_WINDOW(obj),"applications_email_viewer");
442 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
444 ModestMsgViewWindowPrivate *priv = NULL;
446 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
448 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
450 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
452 if (priv->progress_bar_timeout > 0) {
453 g_source_remove (priv->progress_bar_timeout);
454 priv->progress_bar_timeout = 0;
461 set_toolbar_mode (ModestMsgViewWindow *self,
462 ModestToolBarModes mode)
464 ModestWindowPrivate *parent_priv;
465 ModestMsgViewWindowPrivate *priv;
466 /* GtkWidget *widget = NULL; */
468 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
470 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
471 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
473 /* Sets current toolbar mode */
474 priv->current_toolbar_mode = mode;
476 /* Update toolbar dimming state */
477 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
480 case TOOLBAR_MODE_NORMAL:
481 if (priv->progress_toolitem) {
482 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
483 gtk_widget_hide (priv->progress_toolitem);
486 if (priv->progress_bar)
487 gtk_widget_hide (priv->progress_bar);
489 if (priv->cancel_toolitem)
490 gtk_widget_hide (priv->cancel_toolitem);
492 if (priv->prev_toolitem)
493 gtk_widget_show (priv->prev_toolitem);
495 if (priv->next_toolitem)
496 gtk_widget_show (priv->next_toolitem);
498 /* Hide toolbar if optimized view is enabled */
499 if (priv->optimized_view) {
500 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
501 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
505 case TOOLBAR_MODE_TRANSFER:
506 if (priv->prev_toolitem)
507 gtk_widget_hide (priv->prev_toolitem);
509 if (priv->next_toolitem)
510 gtk_widget_hide (priv->next_toolitem);
512 if (priv->progress_bar)
513 gtk_widget_show (priv->progress_bar);
515 if (priv->progress_toolitem) {
516 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
517 gtk_widget_show (priv->progress_toolitem);
520 if (priv->cancel_toolitem)
521 gtk_widget_show (priv->cancel_toolitem);
523 /* Show toolbar if it's hiden (optimized view ) */
524 if (priv->optimized_view) {
525 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
526 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
531 g_return_if_reached ();
538 menubar_to_menu (GtkUIManager *ui_manager)
540 GtkWidget *main_menu;
542 /* Get the menubar from the UI manager */
543 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
549 init_window (ModestMsgViewWindow *obj)
551 GtkWidget *main_vbox;
552 ModestMsgViewWindowPrivate *priv;
553 ModestWindowPrivate *parent_priv;
555 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
556 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
558 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
559 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
560 main_vbox = gtk_vbox_new (FALSE, 6);
562 #ifdef MODEST_USE_MOZEMBED
563 priv->main_scroll = priv->msg_view;
564 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
566 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
567 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
569 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
570 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
571 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
573 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
574 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
576 priv->find_toolbar = hildon_find_toolbar_new (NULL);
577 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
578 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
580 gtk_widget_show_all (GTK_WIDGET(main_vbox));
584 modest_msg_view_window_disconnect_signals (ModestWindow *self)
586 ModestMsgViewWindowPrivate *priv;
587 ModestHeaderView *header_view = NULL;
588 ModestWindow *main_window = NULL;
590 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
592 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
593 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
594 priv->clipboard_change_handler))
595 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
596 priv->clipboard_change_handler);
598 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
599 priv->queue_change_handler))
600 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
601 priv->queue_change_handler);
603 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
604 priv->account_removed_handler))
605 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
606 priv->account_removed_handler);
608 if (priv->header_model) {
609 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
610 priv->row_changed_handler))
611 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
612 priv->row_changed_handler);
614 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
615 priv->row_deleted_handler))
616 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
617 priv->row_deleted_handler);
619 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
620 priv->row_inserted_handler))
621 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
622 priv->row_inserted_handler);
624 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
625 priv->rows_reordered_handler))
626 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
627 priv->rows_reordered_handler);
630 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
631 priv->sighandlers = NULL;
633 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
634 FALSE); /* don't create */
638 header_view = MODEST_HEADER_VIEW(
639 modest_main_window_get_child_widget(
640 MODEST_MAIN_WINDOW(main_window),
641 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
642 if (header_view == NULL)
645 modest_header_view_remove_observer(header_view,
646 MODEST_HEADER_VIEW_OBSERVER(self));
650 modest_msg_view_window_finalize (GObject *obj)
652 ModestMsgViewWindowPrivate *priv;
654 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
656 /* Sanity check: shouldn't be needed, the window mgr should
657 call this function before */
658 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
660 if (priv->header_model != NULL) {
661 g_object_unref (priv->header_model);
662 priv->header_model = NULL;
665 if (priv->progress_bar_timeout > 0) {
666 g_source_remove (priv->progress_bar_timeout);
667 priv->progress_bar_timeout = 0;
670 if (priv->remove_attachment_banner) {
671 gtk_widget_destroy (priv->remove_attachment_banner);
672 g_object_unref (priv->remove_attachment_banner);
673 priv->remove_attachment_banner = NULL;
676 if (priv->purge_timeout > 0) {
677 g_source_remove (priv->purge_timeout);
678 priv->purge_timeout = 0;
681 if (priv->row_reference) {
682 gtk_tree_row_reference_free (priv->row_reference);
683 priv->row_reference = NULL;
686 if (priv->next_row_reference) {
687 gtk_tree_row_reference_free (priv->next_row_reference);
688 priv->next_row_reference = NULL;
692 g_free (priv->msg_uid);
693 priv->msg_uid = NULL;
696 G_OBJECT_CLASS(parent_class)->finalize (obj);
700 select_next_valid_row (GtkTreeModel *model,
701 GtkTreeRowReference **row_reference,
704 GtkTreeIter tmp_iter;
705 GtkTreePath *path, *next;
706 gboolean retval = FALSE;
708 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
710 path = gtk_tree_row_reference_get_path (*row_reference);
711 gtk_tree_model_get_iter (model, &tmp_iter, path);
712 gtk_tree_row_reference_free (*row_reference);
713 *row_reference = NULL;
715 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
716 next = gtk_tree_model_get_path (model, &tmp_iter);
717 *row_reference = gtk_tree_row_reference_new (model, next);
719 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
720 next = gtk_tree_model_get_path (model, &tmp_iter);
722 /* Ensure that we are not selecting the same */
723 if (gtk_tree_path_compare (path, next) != 0) {
724 *row_reference = gtk_tree_row_reference_new (model, next);
730 gtk_tree_path_free (path);
735 /* TODO: This should be in _init(), with the parameters as properties. */
737 modest_msg_view_window_construct (ModestMsgViewWindow *self,
738 const gchar *modest_account_name,
739 const gchar *msg_uid)
742 ModestMsgViewWindowPrivate *priv = NULL;
743 ModestWindowPrivate *parent_priv = NULL;
744 ModestDimmingRulesGroup *menu_rules_group = NULL;
745 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
746 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
748 obj = G_OBJECT (self);
749 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
750 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
752 priv->msg_uid = g_strdup (msg_uid);
755 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
756 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
757 gtk_widget_show (parent_priv->menubar);
758 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
760 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
761 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
762 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
764 /* Add common dimming rules */
765 modest_dimming_rules_group_add_rules (menu_rules_group,
766 modest_msg_view_menu_dimming_entries,
767 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
768 MODEST_WINDOW (self));
769 modest_dimming_rules_group_add_rules (toolbar_rules_group,
770 modest_msg_view_toolbar_dimming_entries,
771 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
772 MODEST_WINDOW (self));
773 modest_dimming_rules_group_add_rules (clipboard_rules_group,
774 modest_msg_view_clipboard_dimming_entries,
775 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
776 MODEST_WINDOW (self));
778 /* Insert dimming rules group for this window */
779 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
780 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
781 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
782 g_object_unref (menu_rules_group);
783 g_object_unref (toolbar_rules_group);
784 g_object_unref (clipboard_rules_group);
786 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
788 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
790 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);
791 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
792 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
793 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
794 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
795 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
796 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
797 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
798 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
799 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
800 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
802 g_signal_connect (G_OBJECT (obj), "key-release-event",
803 G_CALLBACK (modest_msg_view_window_key_event),
806 g_signal_connect (G_OBJECT (obj), "key-press-event",
807 G_CALLBACK (modest_msg_view_window_key_event),
810 g_signal_connect (G_OBJECT (obj), "window-state-event",
811 G_CALLBACK (modest_msg_view_window_window_state_event),
814 g_signal_connect (G_OBJECT (obj), "move-focus",
815 G_CALLBACK (on_move_focus), obj);
817 /* Mail Operation Queue */
818 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
820 G_CALLBACK (on_queue_changed),
823 /* Account manager */
824 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
826 G_CALLBACK(on_account_removed),
829 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
831 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
832 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
833 priv->last_search = NULL;
835 /* Init the clipboard actions dim status */
836 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
838 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
840 /* Check toolbar dimming rules */
841 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
842 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
846 /* FIXME: parameter checks */
848 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
849 const gchar *modest_account_name,
850 const gchar *msg_uid,
852 GtkTreeRowReference *row_reference)
854 ModestMsgViewWindow *window = NULL;
855 ModestMsgViewWindowPrivate *priv = NULL;
856 TnyFolder *header_folder = NULL;
857 ModestHeaderView *header_view = NULL;
858 ModestWindow *main_window = NULL;
859 ModestWindowMgr *mgr = NULL;
861 mgr = modest_runtime_get_window_mgr ();
862 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
863 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
865 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
867 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
869 /* Remember the message list's TreeModel so we can detect changes
870 * and change the list selection when necessary: */
872 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
874 g_warning ("%s: BUG: no main window", __FUNCTION__);
878 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
879 MODEST_MAIN_WINDOW(main_window),
880 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
881 if (header_view != NULL){
882 header_folder = modest_header_view_get_folder(header_view);
883 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) == TNY_FOLDER_TYPE_OUTBOX);
884 g_assert(header_folder != NULL);
885 priv->header_folder_id = tny_folder_get_id(header_folder);
886 g_assert(priv->header_folder_id != NULL);
887 g_object_unref(header_folder);
890 priv->header_model = g_object_ref(model);
891 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
892 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
893 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
895 priv->row_changed_handler = g_signal_connect(
896 GTK_TREE_MODEL(model), "row-changed",
897 G_CALLBACK(modest_msg_view_window_on_row_changed),
899 priv->row_deleted_handler = g_signal_connect(
900 GTK_TREE_MODEL(model), "row-deleted",
901 G_CALLBACK(modest_msg_view_window_on_row_deleted),
903 priv->row_inserted_handler = g_signal_connect (
904 GTK_TREE_MODEL(model), "row-inserted",
905 G_CALLBACK(modest_msg_view_window_on_row_inserted),
907 priv->rows_reordered_handler = g_signal_connect(
908 GTK_TREE_MODEL(model), "rows-reordered",
909 G_CALLBACK(modest_msg_view_window_on_row_reordered),
912 if (header_view != NULL){
913 modest_header_view_add_observer(header_view,
914 MODEST_HEADER_VIEW_OBSERVER(window));
917 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
918 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
919 gtk_widget_show_all (GTK_WIDGET (window));
921 modest_msg_view_window_update_priority (window);
923 /* Check toolbar dimming rules */
924 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
926 return MODEST_WINDOW(window);
930 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
931 const gchar *modest_account_name,
932 const gchar *msg_uid)
934 ModestMsgViewWindow *window = NULL;
935 ModestMsgViewWindowPrivate *priv = NULL;
936 ModestWindowMgr *mgr = NULL;
938 mgr = modest_runtime_get_window_mgr ();
939 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
940 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
941 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
943 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
945 /* Remember that this is a search result,
946 * so we can disable some UI appropriately: */
947 priv->is_search_result = TRUE;
949 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
950 update_window_title (window);
952 return MODEST_WINDOW(window);
956 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
957 const gchar *modest_account_name,
958 const gchar *msg_uid)
961 ModestMsgViewWindowPrivate *priv;
962 ModestWindowMgr *mgr = NULL;
964 g_return_val_if_fail (msg, NULL);
965 mgr = modest_runtime_get_window_mgr ();
966 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
967 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
968 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
969 modest_account_name, msg_uid);
971 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
972 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
974 return MODEST_WINDOW(obj);
977 void modest_msg_view_window_on_row_changed(
978 GtkTreeModel *header_model,
981 ModestMsgViewWindow *window){
982 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
985 void modest_msg_view_window_on_row_deleted(
986 GtkTreeModel *header_model,
988 ModestMsgViewWindow *window){
989 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
992 /* On insertions we check if the folder still has the message we are
993 * showing or do not. If do not, we do nothing. Which means we are still
994 * not attached to any header folder and thus next/prev buttons are
995 * still dimmed. Once the message that is shown by msg-view is found, the
996 * new model of header-view will be attached and the references will be set.
997 * On each further insertions dimming rules will be checked. However
998 * this requires extra CPU time at least works.
999 * (An message might be deleted from TnyFolder and thus will not be
1000 * inserted into the model again for example if it is removed by the
1001 * imap server and the header view is refreshed.)
1003 void modest_msg_view_window_on_row_inserted(
1004 GtkTreeModel *new_model,
1005 GtkTreePath *tree_path,
1006 GtkTreeIter *tree_iter,
1007 ModestMsgViewWindow *window){
1008 ModestMsgViewWindowPrivate *priv = NULL;
1009 TnyHeader *header = NULL;
1012 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1014 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1016 /* If we already has a model attached then the message shown by
1017 * msg-view is in it, and thus we do not need any actions but
1018 * to check the dimming rules.*/
1019 if(priv->header_model != NULL){
1020 gtk_tree_row_reference_free(priv->next_row_reference);
1021 priv->next_row_reference = gtk_tree_row_reference_copy(
1022 priv->row_reference);
1023 select_next_valid_row (priv->header_model,
1024 &(priv->next_row_reference), FALSE);
1025 modest_ui_actions_check_toolbar_dimming_rules (
1026 MODEST_WINDOW (window));
1030 /* Check if the newly inserted message is the same we are actually
1031 * showing. IF not, we should remain detached from the header model
1032 * and thus prev and next toolbarbuttons should remain dimmed. */
1033 gtk_tree_model_get (new_model, tree_iter,
1034 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1035 uid = modest_tny_folder_get_header_unique_id(header);
1036 g_object_unref(G_OBJECT(header));
1038 if(!g_str_equal(priv->msg_uid, uid)){
1044 /* Setup row_reference for the actual msg. */
1045 priv->row_reference = gtk_tree_row_reference_new(
1046 new_model, tree_path);
1047 if(priv->row_reference == NULL){
1048 g_warning("No reference for msg header item.");
1052 /* Attach new_model and connect some callback to it to become able
1053 * to detect changes in header-view. */
1054 priv->header_model = g_object_ref(new_model);
1055 g_signal_connect (new_model, "row-changed",
1056 G_CALLBACK (modest_msg_view_window_on_row_changed),
1058 g_signal_connect (new_model, "row-deleted",
1059 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1061 g_signal_connect (new_model, "rows-reordered",
1062 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1065 /* Now set up next_row_reference. */
1066 priv->next_row_reference = gtk_tree_row_reference_copy(
1067 priv->row_reference);
1068 select_next_valid_row (priv->header_model,
1069 &(priv->next_row_reference), FALSE);
1071 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1074 void modest_msg_view_window_on_row_reordered(
1075 GtkTreeModel *header_model,
1079 ModestMsgViewWindow *window){
1080 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1083 /* The modest_msg_view_window_update_model_replaced implements update
1084 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1085 * actually belongs to the header-view is the same as the TnyFolder of
1086 * the message of msg-view or not. If they are different, there is
1087 * nothing to do. If they are the same, then the model has replaced and
1088 * the reference in msg-view shall be replaced from the old model to
1089 * the new model. In this case the view will be detached from it's
1090 * header folder. From this point the next/prev buttons are dimmed.
1092 void modest_msg_view_window_update_model_replaced(
1093 ModestHeaderViewObserver *observer,
1094 GtkTreeModel *model,
1095 const gchar *tny_folder_id){
1096 ModestMsgViewWindowPrivate *priv = NULL;
1097 ModestMsgViewWindow *window = NULL;
1099 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1100 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1102 window = MODEST_MSG_VIEW_WINDOW(observer);
1103 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1105 /* If there is an other folder in the header-view then we do
1106 * not care about it's model (msg list). Else if the
1107 * header-view shows the folder the msg shown by us is in, we
1108 * shall replace our model reference and make some check. */
1109 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1112 /* Model is changed(replaced), so we should forget the old
1113 * one. Because there might be other references and there
1114 * might be some change on the model even if we unreferenced
1115 * it, we need to disconnect our signals here. */
1116 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1117 priv->row_changed_handler))
1118 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1119 priv->row_changed_handler);
1120 priv->row_changed_handler = 0;
1121 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1122 priv->row_deleted_handler))
1123 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1124 priv->row_deleted_handler);
1125 priv->row_deleted_handler = 0;
1126 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1127 priv->row_inserted_handler))
1128 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1129 priv->row_inserted_handler);
1130 priv->row_inserted_handler = 0;
1131 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1132 priv->rows_reordered_handler))
1133 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1134 priv->rows_reordered_handler);
1135 priv->rows_reordered_handler = 0;
1136 g_object_unref(priv->header_model);
1137 priv->header_model = NULL;
1138 g_object_unref(priv->row_reference);
1139 priv->row_reference = NULL;
1140 g_object_unref(priv->next_row_reference);
1141 priv->next_row_reference = NULL;
1143 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1145 g_assert(model != NULL);
1147 /* Also we must connect to the new model for row insertions.
1148 * Only for insertions now. We will need other ones only after
1149 * the msg is show by msg-view is added to the new model. */
1150 priv->row_inserted_handler = g_signal_connect (
1151 model, "row-inserted",
1152 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1157 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1159 ModestMsgViewWindowPrivate *priv= NULL;
1161 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1162 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1164 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1168 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1170 ModestMsgViewWindowPrivate *priv= NULL;
1172 TnyHeader *header = NULL;
1173 GtkTreePath *path = NULL;
1176 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1177 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1179 /* If the message was not obtained from a treemodel,
1180 * for instance if it was opened directly by the search UI:
1182 if (priv->header_model == NULL) {
1183 msg = modest_msg_view_window_get_message (self);
1185 header = tny_msg_get_header (msg);
1186 g_object_unref (msg);
1191 /* Get iter of the currently selected message in the header view: */
1192 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1193 * instead of sometimes retrieving it from the header view?
1194 * Then we wouldn't be dependent on the message actually still being selected
1195 * in the header view. murrayc. */
1196 if (!gtk_tree_row_reference_valid (priv->row_reference))
1198 path = gtk_tree_row_reference_get_path (priv->row_reference);
1199 g_return_val_if_fail (path != NULL, NULL);
1200 gtk_tree_model_get_iter (priv->header_model,
1204 /* Get current message header */
1205 gtk_tree_model_get (priv->header_model, &iter,
1206 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1209 gtk_tree_path_free (path);
1214 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1216 ModestMsgViewWindowPrivate *priv;
1218 g_return_val_if_fail (self, NULL);
1220 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1222 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1226 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1228 ModestMsgViewWindowPrivate *priv;
1230 g_return_val_if_fail (self, NULL);
1232 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1234 return (const gchar*) priv->msg_uid;
1238 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1241 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1242 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1243 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1247 is_active = gtk_toggle_action_get_active (toggle);
1250 gtk_widget_show (priv->find_toolbar);
1251 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1253 gtk_widget_hide (priv->find_toolbar);
1256 /* update the toggle buttons status */
1257 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1258 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1259 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1260 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1265 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1266 ModestMsgViewWindow *obj)
1268 GtkToggleAction *toggle;
1269 ModestWindowPrivate *parent_priv;
1270 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1272 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1273 gtk_toggle_action_set_active (toggle, FALSE);
1277 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1278 ModestMsgViewWindow *obj)
1280 gchar *current_search;
1281 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1283 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1284 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1288 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1290 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1291 g_free (current_search);
1292 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1296 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1298 g_free (priv->last_search);
1299 priv->last_search = g_strdup (current_search);
1300 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1303 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1304 g_free (priv->last_search);
1305 priv->last_search = NULL;
1307 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1310 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1311 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1312 g_free (priv->last_search);
1313 priv->last_search = NULL;
1315 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1319 g_free (current_search);
1324 modest_msg_view_window_set_zoom (ModestWindow *window,
1327 ModestMsgViewWindowPrivate *priv;
1328 ModestWindowPrivate *parent_priv;
1329 GtkAction *action = NULL;
1330 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1332 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1334 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1335 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1336 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1338 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1339 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1341 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1345 modest_msg_view_window_get_zoom (ModestWindow *window)
1347 ModestMsgViewWindowPrivate *priv;
1349 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1351 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1352 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1356 modest_msg_view_window_zoom_plus (ModestWindow *window)
1358 ModestWindowPrivate *parent_priv;
1359 GtkRadioAction *zoom_radio_action;
1360 GSList *group, *node;
1362 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1363 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1364 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1366 group = gtk_radio_action_get_group (zoom_radio_action);
1368 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1369 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1373 for (node = group; node != NULL; node = g_slist_next (node)) {
1374 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1375 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1383 modest_msg_view_window_zoom_minus (ModestWindow *window)
1385 ModestWindowPrivate *parent_priv;
1386 GtkRadioAction *zoom_radio_action;
1387 GSList *group, *node;
1389 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1390 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1391 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1393 group = gtk_radio_action_get_group (zoom_radio_action);
1395 for (node = group; node != NULL; node = g_slist_next (node)) {
1396 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1397 if (node->next != NULL) {
1398 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1401 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1411 modest_msg_view_window_key_event (GtkWidget *window,
1416 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1417 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1418 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1419 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1420 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1421 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1422 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1423 gboolean return_value;
1425 if (event->type == GDK_KEY_RELEASE) {
1426 GtkScrollType scroll_type;
1428 switch (event->keyval) {
1431 scroll_type = GTK_SCROLL_STEP_UP; break;
1434 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1436 case GDK_KP_Page_Up:
1437 scroll_type = GTK_SCROLL_PAGE_UP; break;
1439 case GDK_KP_Page_Down:
1440 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1443 scroll_type = GTK_SCROLL_START; break;
1446 scroll_type = GTK_SCROLL_END; break;
1447 default: scroll_type = GTK_SCROLL_NONE;
1450 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1451 scroll_type, FALSE, &return_value);
1462 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1465 ModestMsgViewWindowPrivate *priv;
1466 GtkTreeIter tmp_iter;
1467 gboolean is_last_selected;
1469 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1470 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1472 /*if no model (so no rows at all), then virtually we are the last*/
1473 if (!priv->header_model)
1476 path = gtk_tree_row_reference_get_path (priv->row_reference);
1480 is_last_selected = TRUE;
1481 while (is_last_selected) {
1483 gtk_tree_path_next (path);
1484 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1486 gtk_tree_model_get (priv->header_model, &tmp_iter,
1487 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1490 if (msg_is_visible (header, priv->is_outbox))
1491 is_last_selected = FALSE;
1492 g_object_unref(G_OBJECT(header));
1495 gtk_tree_path_free (path);
1496 return is_last_selected;
1500 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1502 ModestMsgViewWindowPrivate *priv;
1504 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1505 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1507 return priv->header_model != NULL;
1511 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1513 ModestMsgViewWindowPrivate *priv;
1515 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1516 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1518 return priv->is_search_result;
1522 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1524 return (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) &&
1525 ( (!check_outbox) || (modest_tny_all_send_queues_get_msg_status (header) != MODEST_TNY_SEND_QUEUE_FAILED)) ;
1530 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1533 ModestMsgViewWindowPrivate *priv;
1534 gboolean is_first_selected;
1535 GtkTreeIter tmp_iter;
1536 /* gchar * path_string;*/
1538 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1539 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1541 /*if no model (so no rows at all), then virtually we are the first*/
1542 if (!priv->header_model)
1545 path = gtk_tree_row_reference_get_path (priv->row_reference);
1549 /* path_string = gtk_tree_path_to_string (path);
1550 is_first_selected = strcmp (path_string, "0");
1552 g_free (path_string);
1553 gtk_tree_path_free (path);
1555 return is_first_selected;*/
1557 is_first_selected = TRUE;
1558 while (is_first_selected) {
1560 if(!gtk_tree_path_prev (path))
1562 /* Here the 'if' is needless for logic, but let make sure
1563 * iter is valid for gtk_tree_model_get. */
1564 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1566 gtk_tree_model_get (priv->header_model, &tmp_iter,
1567 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1570 if (msg_is_visible (header, priv->is_outbox))
1571 is_first_selected = FALSE;
1572 g_object_unref(G_OBJECT(header));
1575 gtk_tree_path_free (path);
1576 return is_first_selected;
1580 * Reads the message whose summary item is @header. It takes care of
1581 * several things, among others:
1583 * If the message was not previously downloaded then ask the user
1584 * before downloading. If there is no connection launch the connection
1585 * dialog. Update toolbar dimming rules.
1587 * Returns: TRUE if the mail operation was started, otherwise if the
1588 * user do not want to download the message, or if the user do not
1589 * want to connect, then the operation is not issued
1592 message_reader (ModestMsgViewWindow *window,
1593 ModestMsgViewWindowPrivate *priv,
1595 GtkTreeRowReference *row_reference)
1597 ModestMailOperation *mail_op = NULL;
1598 gboolean already_showing = FALSE;
1599 ModestWindow *msg_window = NULL;
1600 ModestWindowMgr *mgr;
1602 g_return_val_if_fail (row_reference != NULL, FALSE);
1604 mgr = modest_runtime_get_window_mgr ();
1605 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1606 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1609 gtk_window_present (GTK_WINDOW (msg_window));
1610 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1614 /* Msg download completed */
1615 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1616 /* Ask the user if he wants to download the message if
1618 if (!tny_device_is_online (modest_runtime_get_device())) {
1619 TnyFolder *folder = NULL;
1620 GtkResponseType response;
1622 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1623 _("mcen_nc_get_msg"));
1624 if (response == GTK_RESPONSE_CANCEL)
1627 /* Offer the connection dialog if necessary */
1628 folder = tny_header_get_folder (header);
1630 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1631 TNY_FOLDER_STORE (folder))) {
1632 g_object_unref (folder);
1635 g_object_unref (folder);
1640 /* New mail operation */
1641 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1642 modest_ui_actions_get_msgs_full_error_handler,
1645 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1646 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1647 g_object_unref (mail_op);
1649 /* Update toolbar dimming rules */
1650 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1656 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1658 ModestMsgViewWindowPrivate *priv;
1659 GtkTreePath *path= NULL;
1660 GtkTreeIter tmp_iter;
1662 gboolean retval = TRUE;
1663 GtkTreeRowReference *row_reference = NULL;
1665 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1666 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1668 /* Update the next row reference if it's not valid. This could
1669 happen if for example the header which it was pointing to,
1670 was deleted. The best place to do it is in the row-deleted
1671 handler but the tinymail model do not work like the glib
1672 tree models and reports the deletion when the row is still
1674 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1675 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1676 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1677 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1680 if (priv->next_row_reference)
1681 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1685 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1687 gtk_tree_model_get_iter (priv->header_model,
1690 gtk_tree_path_free (path);
1692 gtk_tree_model_get (priv->header_model, &tmp_iter,
1693 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1696 /* Read the message & show it */
1697 if (!message_reader (window, priv, header, row_reference)) {
1699 gtk_tree_row_reference_free (row_reference);
1703 g_object_unref (header);
1709 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1711 ModestMsgViewWindowPrivate *priv = NULL;
1712 TnyHeader *header = NULL;
1714 GtkTreePath *path = NULL;
1715 GtkTreeRowReference *row_reference = NULL;
1717 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1718 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1720 /* Check that the model is not empty */
1721 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1724 /* Get the header */
1725 gtk_tree_model_get (priv->header_model,
1727 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1729 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1730 if (!msg_is_visible (header, priv->is_outbox)) {
1731 g_object_unref (header);
1732 return modest_msg_view_window_select_next_message (self);
1735 path = gtk_tree_model_get_path (priv->header_model, &iter);
1736 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1737 gtk_tree_path_free (path);
1739 /* Read the message & show it */
1740 message_reader (self, priv, header, row_reference);
1743 g_object_unref (header);
1749 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1751 ModestMsgViewWindowPrivate *priv = NULL;
1753 GtkTreeRowReference *row_reference = NULL;
1755 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1756 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1758 /* Return inmediatly if there is no header model */
1759 if (!priv->header_model)
1762 path = gtk_tree_row_reference_get_path (priv->row_reference);
1763 while (gtk_tree_path_prev (path)) {
1767 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1768 gtk_tree_model_get (priv->header_model, &iter,
1769 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1773 if (!msg_is_visible (header, priv->is_outbox)) {
1774 g_object_unref (header);
1778 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1779 /* Read the message & show it */
1780 if (!message_reader (window, priv, header, row_reference)) {
1781 gtk_tree_row_reference_free (row_reference);
1782 g_object_unref (header);
1786 gtk_tree_path_free (path);
1787 g_object_unref (header);
1792 gtk_tree_path_free (path);
1797 view_msg_cb (ModestMailOperation *mail_op,
1804 ModestMsgViewWindow *self = NULL;
1805 ModestMsgViewWindowPrivate *priv = NULL;
1806 GtkTreeRowReference *row_reference = NULL;
1808 /* If there was any error */
1809 row_reference = (GtkTreeRowReference *) user_data;
1810 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1811 gtk_tree_row_reference_free (row_reference);
1815 /* Get the window */
1816 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1817 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1818 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1820 /* Update the row reference */
1821 gtk_tree_row_reference_free (priv->row_reference);
1822 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1823 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1824 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1825 gtk_tree_row_reference_free (row_reference);
1827 /* Mark header as read */
1828 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1829 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1831 /* Set new message */
1832 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1833 modest_msg_view_window_update_priority (self);
1834 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1835 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1837 /* Set the new message uid of the window */
1838 if (priv->msg_uid) {
1839 g_free (priv->msg_uid);
1840 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1843 /* Notify the observers */
1844 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1845 0, priv->header_model, priv->row_reference);
1847 /* Free new references */
1848 g_object_unref (self);
1852 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1854 ModestMsgViewWindowPrivate *priv;
1856 TnyFolderType folder_type;
1858 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1860 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1862 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1866 folder = tny_msg_get_folder (msg);
1868 folder_type = tny_folder_get_folder_type (folder);
1869 g_object_unref (folder);
1871 g_object_unref (msg);
1879 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1881 ModestMsgViewWindowPrivate *priv;
1882 TnyHeaderFlags flags = 0;
1884 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1886 if (priv->header_model) {
1889 GtkTreePath *path = NULL;
1891 path = gtk_tree_row_reference_get_path (priv->row_reference);
1892 g_return_if_fail (path != NULL);
1893 gtk_tree_model_get_iter (priv->header_model,
1895 gtk_tree_row_reference_get_path (priv->row_reference));
1897 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1900 flags = tny_header_get_flags (header);
1901 g_object_unref(G_OBJECT(header));
1903 gtk_tree_path_free (path);
1906 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1911 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1913 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1914 ModestWindowPrivate *parent_priv;
1915 ModestWindowMgr *mgr;
1916 gboolean is_fullscreen;
1917 GtkAction *fs_toggle_action;
1920 mgr = modest_runtime_get_window_mgr ();
1921 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1923 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1925 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1926 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1927 if (is_fullscreen != active) {
1928 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1937 set_homogeneous (GtkWidget *widget,
1940 if (GTK_IS_TOOL_ITEM (widget)) {
1941 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1942 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1947 modest_msg_view_window_show_toolbar (ModestWindow *self,
1948 gboolean show_toolbar)
1950 ModestMsgViewWindowPrivate *priv = NULL;
1951 ModestWindowPrivate *parent_priv;
1952 GtkWidget *reply_button = NULL, *menu = NULL;
1953 GtkWidget *placeholder = NULL;
1955 const gchar *action_name;
1958 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1959 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1961 /* Set optimized view status */
1962 priv->optimized_view = !show_toolbar;
1964 if (!parent_priv->toolbar) {
1965 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1967 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1969 /* Set homogeneous toolbar */
1970 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1971 set_homogeneous, NULL);
1973 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1974 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1975 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1976 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1977 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1978 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1979 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1980 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1982 /* Add ProgressBar (Transfer toolbar) */
1983 priv->progress_bar = modest_progress_bar_widget_new ();
1984 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1985 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1986 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1987 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1988 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1990 /* Connect cancel 'clicked' signal to abort progress mode */
1991 g_signal_connect(priv->cancel_toolitem, "clicked",
1992 G_CALLBACK(cancel_progressbar),
1995 /* Add it to the observers list */
1996 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1999 hildon_window_add_toolbar (HILDON_WINDOW (self),
2000 GTK_TOOLBAR (parent_priv->toolbar));
2002 /* Set reply button tap and hold menu */
2003 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2004 "/ToolBar/ToolbarMessageReply");
2005 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2006 "/ToolbarReplyCSM");
2007 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2011 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2012 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2013 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2015 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2016 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2017 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2019 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2022 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2023 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2026 /* Update also the actions (to update the toggles in the
2027 menus), we have to do it manually because some other window
2028 of the same time could have changed it (remember that the
2029 toolbar fullscreen mode is shared by all the windows of the
2031 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2032 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2034 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2036 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2037 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2042 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2044 ModestMsgViewWindow *window)
2046 if (!GTK_WIDGET_VISIBLE (window))
2049 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2053 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2055 ModestMsgViewWindowPrivate *priv;
2057 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2058 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2060 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2064 cancel_progressbar (GtkToolButton *toolbutton,
2065 ModestMsgViewWindow *self)
2068 ModestMsgViewWindowPrivate *priv;
2070 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2072 /* Get operation observers and cancel its current operation */
2073 tmp = priv->progress_widgets;
2075 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2076 tmp=g_slist_next(tmp);
2080 observers_empty (ModestMsgViewWindow *self)
2083 ModestMsgViewWindowPrivate *priv;
2084 gboolean is_empty = TRUE;
2085 guint pending_ops = 0;
2087 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2088 tmp = priv->progress_widgets;
2090 /* Check all observers */
2091 while (tmp && is_empty) {
2092 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2093 is_empty = pending_ops == 0;
2095 tmp = g_slist_next(tmp);
2102 on_account_removed (TnyAccountStore *account_store,
2103 TnyAccount *account,
2106 /* Do nothing if it's a transport account, because we only
2107 show the messages of a store account */
2108 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2109 const gchar *parent_acc = NULL;
2110 const gchar *our_acc = NULL;
2112 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2113 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2115 /* Close this window if I'm showing a message of the removed account */
2116 if (strcmp (parent_acc, our_acc) == 0)
2117 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2122 on_mail_operation_started (ModestMailOperation *mail_op,
2125 ModestMsgViewWindow *self;
2126 ModestMailOperationTypeOperation op_type;
2128 ModestMsgViewWindowPrivate *priv;
2130 self = MODEST_MSG_VIEW_WINDOW (user_data);
2131 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2132 op_type = modest_mail_operation_get_type_operation (mail_op);
2133 tmp = priv->progress_widgets;
2135 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2136 set_toolbar_transfer_mode(self);
2138 modest_progress_object_add_operation (
2139 MODEST_PROGRESS_OBJECT (tmp->data),
2141 tmp = g_slist_next (tmp);
2147 on_mail_operation_finished (ModestMailOperation *mail_op,
2150 ModestMsgViewWindow *self;
2151 ModestMailOperationTypeOperation op_type;
2153 ModestMsgViewWindowPrivate *priv;
2155 self = MODEST_MSG_VIEW_WINDOW (user_data);
2156 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2157 op_type = modest_mail_operation_get_type_operation (mail_op);
2158 tmp = priv->progress_widgets;
2160 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2162 modest_progress_object_remove_operation (
2163 MODEST_PROGRESS_OBJECT (tmp->data),
2165 tmp = g_slist_next (tmp);
2168 /* If no more operations are being observed, NORMAL mode is enabled again */
2169 if (observers_empty (self)) {
2170 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2176 on_queue_changed (ModestMailOperationQueue *queue,
2177 ModestMailOperation *mail_op,
2178 ModestMailOperationQueueNotification type,
2179 ModestMsgViewWindow *self)
2181 ModestMsgViewWindowPrivate *priv;
2183 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2185 /* If this operations was created by another window, do nothing */
2186 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2189 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2190 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2192 "operation-started",
2193 G_CALLBACK (on_mail_operation_started),
2195 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2197 "operation-finished",
2198 G_CALLBACK (on_mail_operation_finished),
2200 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2201 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2203 "operation-started");
2204 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2206 "operation-finished");
2211 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2213 ModestMsgViewWindowPrivate *priv;
2214 GList *selected_attachments = NULL;
2216 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2217 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2219 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2221 return selected_attachments;
2225 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2227 ModestMsgViewWindowPrivate *priv;
2228 const gchar *msg_uid;
2229 gchar *attachment_uid = NULL;
2230 gint attachment_index = 0;
2233 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2234 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2235 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2237 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2238 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2239 attachment_index = g_list_index (attachments, mime_part);
2240 g_list_free (attachments);
2242 if (msg_uid && attachment_index >= 0) {
2243 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2246 if (mime_part == NULL) {
2247 gboolean error = FALSE;
2248 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2249 if (selected_attachments == NULL) {
2251 } else if (g_list_length (selected_attachments) > 1) {
2252 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2255 mime_part = (TnyMimePart *) selected_attachments->data;
2256 g_object_ref (mime_part);
2258 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2259 g_list_free (selected_attachments);
2264 g_object_ref (mime_part);
2267 if (tny_mime_part_is_purged (mime_part)) {
2268 g_object_unref (mime_part);
2272 if (!TNY_IS_MSG (mime_part)) {
2273 gchar *filepath = NULL;
2274 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2275 const gchar *content_type;
2276 TnyFsStream *temp_stream = NULL;
2277 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2280 if (temp_stream != NULL) {
2281 content_type = tny_mime_part_get_content_type (mime_part);
2282 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2284 /* make the file read-only */
2285 if (g_chmod(filepath, 0444) != 0)
2286 g_warning ("%s: failed to set file '%s' to read-only: %s",
2287 __FUNCTION__, filepath, strerror(errno));
2289 modest_platform_activate_file (filepath, content_type);
2290 g_object_unref (temp_stream);
2292 /* NOTE: files in the temporary area will be automatically
2293 * cleaned after some time if they are no longer in use */
2294 } else if (filepath != NULL) {
2295 /* the file may already exist but it isn't writable,
2296 * let's try to open it anyway */
2297 content_type = tny_mime_part_get_content_type (mime_part);
2298 modest_platform_activate_file (filepath, content_type);
2302 /* message attachment */
2303 TnyHeader *header = NULL;
2304 ModestWindowMgr *mgr;
2305 ModestWindow *msg_win = NULL;
2308 header = tny_msg_get_header (TNY_MSG (mime_part));
2309 mgr = modest_runtime_get_window_mgr ();
2310 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2313 if (msg_win) /* there is already a window for this uid; top it */
2314 gtk_window_present (GTK_WINDOW(msg_win));
2316 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2317 * thus, we don't do anything */
2318 g_warning ("window for is already being created");
2320 /* it's not found, so create a new window for it */
2321 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2322 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2324 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2325 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2326 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2327 modest_window_get_zoom (MODEST_WINDOW (window)));
2328 modest_window_mgr_register_window (mgr, msg_win);
2329 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2330 gtk_widget_show_all (GTK_WIDGET (msg_win));
2333 g_object_unref (mime_part);
2349 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2350 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2351 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2352 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2355 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2359 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2360 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2361 g_free (pair->filename);
2362 g_object_unref (pair->part);
2363 g_slice_free (SaveMimePartPair, pair);
2365 g_list_free (info->pairs);
2368 gtk_widget_destroy (info->banner);
2369 g_object_unref (info->banner);
2370 g_slice_free (SaveMimePartInfo, info);
2375 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2377 if (info->pairs != NULL) {
2378 save_mime_part_to_file (info);
2381 result = info->result;
2383 /* This is a GDK lock because we are an idle callback and
2384 * hildon_banner_show_information is or does Gtk+ code */
2386 gdk_threads_enter (); /* CHECKED */
2387 save_mime_part_info_free (info, TRUE);
2389 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2391 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2393 gdk_threads_leave (); /* CHECKED */
2400 save_mime_part_to_file (SaveMimePartInfo *info)
2402 GnomeVFSResult result;
2403 GnomeVFSHandle *handle;
2405 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2407 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2408 if (result == GNOME_VFS_OK) {
2409 stream = tny_vfs_stream_new (handle);
2410 tny_mime_part_decode_to_stream (pair->part, stream);
2411 g_object_unref (G_OBJECT (stream));
2412 g_object_unref (pair->part);
2413 g_slice_free (SaveMimePartPair, pair);
2414 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2415 info->result = TRUE;
2417 save_mime_part_info_free (info, FALSE);
2418 info->result = FALSE;
2421 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2426 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2428 gboolean is_ok = TRUE;
2429 gint replaced_files = 0;
2430 const GList *files = info->pairs;
2433 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2434 SaveMimePartPair *pair = iter->data;
2435 if (modest_utils_file_exists (pair->filename)) {
2439 if (replaced_files) {
2440 GtkWidget *confirm_overwrite_dialog;
2441 const gchar *message = (replaced_files == 1) ?
2442 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2443 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2444 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2447 gtk_widget_destroy (confirm_overwrite_dialog);
2451 save_mime_part_info_free (info, TRUE);
2453 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2454 _CS("sfil_ib_saving"));
2455 info->banner = g_object_ref (banner);
2456 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2457 g_object_unref (banner);
2464 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2466 gboolean clean_list = FALSE;
2467 ModestMsgViewWindowPrivate *priv;
2468 GList *files_to_save = NULL;
2469 GtkWidget *save_dialog = NULL;
2470 gchar *folder = NULL;
2471 gboolean canceled = FALSE;
2472 const gchar *filename = NULL;
2473 gchar *save_multiple_str = NULL;
2475 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2476 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2478 if (mime_parts == NULL) {
2479 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2480 if (mime_parts == NULL)
2485 /* prepare dialog */
2486 if (mime_parts->next == NULL) {
2487 /* only one attachment selected */
2488 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2489 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2490 filename = tny_mime_part_get_filename (mime_part);
2492 g_warning ("Tried to save a non-file attachment");
2496 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2497 g_list_length (mime_parts));
2500 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2501 GTK_FILE_CHOOSER_ACTION_SAVE);
2504 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2505 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2509 if (filename != NULL)
2510 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2513 /* if multiple, set multiple string */
2514 if (save_multiple_str) {
2515 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2519 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2520 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2522 if (!modest_utils_folder_writable (chooser_uri)) {
2523 hildon_banner_show_information
2524 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2528 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2529 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2531 if (tny_mime_part_is_attachment (mime_part)) {
2532 SaveMimePartPair *pair;
2534 if ((mime_parts->next != NULL) &&
2535 (tny_mime_part_get_filename (mime_part) == NULL))
2538 pair = g_slice_new0 (SaveMimePartPair);
2539 if (mime_parts->next == NULL) {
2540 pair->filename = g_strdup (chooser_uri);
2543 g_build_filename (chooser_uri,
2544 tny_mime_part_get_filename (mime_part), NULL);
2546 pair->part = g_object_ref (mime_part);
2547 files_to_save = g_list_prepend (files_to_save, pair);
2551 g_free (chooser_uri);
2554 gtk_widget_destroy (save_dialog);
2557 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2558 g_list_free (mime_parts);
2561 if (files_to_save != NULL) {
2562 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2563 info->pairs = files_to_save;
2564 info->result = TRUE;
2565 save_mime_parts_to_file_with_checks (info);
2570 show_remove_attachment_information (gpointer userdata)
2572 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2573 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2575 /* We're outside the main lock */
2576 gdk_threads_enter ();
2578 if (priv->remove_attachment_banner != NULL) {
2579 gtk_widget_destroy (priv->remove_attachment_banner);
2580 g_object_unref (priv->remove_attachment_banner);
2583 priv->remove_attachment_banner = g_object_ref (
2584 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2586 gdk_threads_leave ();
2592 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2594 ModestMsgViewWindowPrivate *priv;
2595 GList *mime_parts = NULL, *node;
2596 gchar *confirmation_message;
2600 /* TnyFolder *folder; */
2602 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2603 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2606 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2608 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2610 /* Remove already purged messages from mime parts list */
2612 while (node != NULL) {
2613 TnyMimePart *part = TNY_MIME_PART (node->data);
2614 if (tny_mime_part_is_purged (part)) {
2615 GList *deleted_node = node;
2616 node = g_list_next (node);
2617 g_object_unref (part);
2618 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2620 node = g_list_next (node);
2624 if (mime_parts == NULL)
2627 n_attachments = g_list_length (mime_parts);
2628 if (n_attachments == 1) {
2629 const gchar *filename;
2631 if (TNY_IS_MSG (mime_parts->data)) {
2633 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2634 filename = tny_header_get_subject (header);
2635 g_object_unref (header);
2636 if (filename == NULL)
2637 filename = _("mail_va_no_subject");
2639 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2641 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2643 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2644 "mcen_nc_purge_files_text",
2645 n_attachments), n_attachments);
2647 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2648 confirmation_message);
2649 g_free (confirmation_message);
2651 if (response != GTK_RESPONSE_OK)
2654 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2655 /* folder = tny_msg_get_folder (msg); */
2656 /* tny_msg_uncache_attachments (msg); */
2657 /* tny_folder_refresh (folder, NULL); */
2658 /* g_object_unref (folder); */
2660 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2661 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2662 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2665 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2666 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2667 tny_msg_rewrite_cache (msg);
2668 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2670 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2671 g_list_free (mime_parts);
2673 if (priv->purge_timeout > 0) {
2674 g_source_remove (priv->purge_timeout);
2675 priv->purge_timeout = 0;
2678 if (priv->remove_attachment_banner) {
2679 gtk_widget_destroy (priv->remove_attachment_banner);
2680 g_object_unref (priv->remove_attachment_banner);
2681 priv->remove_attachment_banner = NULL;
2689 update_window_title (ModestMsgViewWindow *window)
2691 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2693 TnyHeader *header = NULL;
2694 const gchar *subject = NULL;
2696 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2699 header = tny_msg_get_header (msg);
2700 subject = tny_header_get_subject (header);
2701 g_object_unref (msg);
2704 if ((subject == NULL)||(subject[0] == '\0'))
2705 subject = _("mail_va_no_subject");
2707 gtk_window_set_title (GTK_WINDOW (window), subject);
2711 static void on_move_focus (GtkWidget *widget,
2712 GtkDirectionType direction,
2715 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");