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));
425 /* Set window icon */
426 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
428 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
429 g_object_unref (window_icon);
433 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
434 GTK_WINDOW(obj),"applications_email_viewer");
439 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
441 ModestMsgViewWindowPrivate *priv = NULL;
443 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
445 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
447 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
449 if (priv->progress_bar_timeout > 0) {
450 g_source_remove (priv->progress_bar_timeout);
451 priv->progress_bar_timeout = 0;
458 set_toolbar_mode (ModestMsgViewWindow *self,
459 ModestToolBarModes mode)
461 ModestWindowPrivate *parent_priv;
462 ModestMsgViewWindowPrivate *priv;
463 /* GtkWidget *widget = NULL; */
465 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
467 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
468 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
470 /* Sets current toolbar mode */
471 priv->current_toolbar_mode = mode;
473 /* Update toolbar dimming state */
474 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
477 case TOOLBAR_MODE_NORMAL:
478 if (priv->progress_toolitem) {
479 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
480 gtk_widget_hide (priv->progress_toolitem);
483 if (priv->progress_bar)
484 gtk_widget_hide (priv->progress_bar);
486 if (priv->cancel_toolitem)
487 gtk_widget_hide (priv->cancel_toolitem);
489 if (priv->prev_toolitem)
490 gtk_widget_show (priv->prev_toolitem);
492 if (priv->next_toolitem)
493 gtk_widget_show (priv->next_toolitem);
495 /* Hide toolbar if optimized view is enabled */
496 if (priv->optimized_view) {
497 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
498 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
502 case TOOLBAR_MODE_TRANSFER:
503 if (priv->prev_toolitem)
504 gtk_widget_hide (priv->prev_toolitem);
506 if (priv->next_toolitem)
507 gtk_widget_hide (priv->next_toolitem);
509 if (priv->progress_bar)
510 gtk_widget_show (priv->progress_bar);
512 if (priv->progress_toolitem) {
513 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
514 gtk_widget_show (priv->progress_toolitem);
517 if (priv->cancel_toolitem)
518 gtk_widget_show (priv->cancel_toolitem);
520 /* Show toolbar if it's hiden (optimized view ) */
521 if (priv->optimized_view) {
522 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
523 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
528 g_return_if_reached ();
535 menubar_to_menu (GtkUIManager *ui_manager)
537 GtkWidget *main_menu;
539 /* Get the menubar from the UI manager */
540 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
546 init_window (ModestMsgViewWindow *obj)
548 GtkWidget *main_vbox;
549 ModestMsgViewWindowPrivate *priv;
550 ModestWindowPrivate *parent_priv;
552 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
553 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
555 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
556 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
557 main_vbox = gtk_vbox_new (FALSE, 6);
559 #ifdef MODEST_USE_MOZEMBED
560 priv->main_scroll = priv->msg_view;
561 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
563 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
564 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
566 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
567 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
568 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
570 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
571 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
573 priv->find_toolbar = hildon_find_toolbar_new (NULL);
574 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
575 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
577 gtk_widget_show_all (GTK_WIDGET(main_vbox));
581 modest_msg_view_window_disconnect_signals (ModestWindow *self)
583 ModestMsgViewWindowPrivate *priv;
584 ModestHeaderView *header_view = NULL;
585 ModestWindow *main_window = NULL;
587 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
589 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
590 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
591 priv->clipboard_change_handler))
592 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
593 priv->clipboard_change_handler);
595 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
596 priv->queue_change_handler))
597 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
598 priv->queue_change_handler);
600 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
601 priv->account_removed_handler))
602 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
603 priv->account_removed_handler);
605 if (priv->header_model) {
606 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
607 priv->row_changed_handler))
608 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
609 priv->row_changed_handler);
611 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
612 priv->row_deleted_handler))
613 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
614 priv->row_deleted_handler);
616 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
617 priv->row_inserted_handler))
618 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
619 priv->row_inserted_handler);
621 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
622 priv->rows_reordered_handler))
623 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
624 priv->rows_reordered_handler);
627 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
628 priv->sighandlers = NULL;
630 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
631 FALSE); /* don't create */
635 header_view = MODEST_HEADER_VIEW(
636 modest_main_window_get_child_widget(
637 MODEST_MAIN_WINDOW(main_window),
638 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
639 if (header_view == NULL)
642 modest_header_view_remove_observer(header_view,
643 MODEST_HEADER_VIEW_OBSERVER(self));
647 modest_msg_view_window_finalize (GObject *obj)
649 ModestMsgViewWindowPrivate *priv;
651 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
653 /* Sanity check: shouldn't be needed, the window mgr should
654 call this function before */
655 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
657 if (priv->header_model != NULL) {
658 g_object_unref (priv->header_model);
659 priv->header_model = NULL;
662 if (priv->progress_bar_timeout > 0) {
663 g_source_remove (priv->progress_bar_timeout);
664 priv->progress_bar_timeout = 0;
667 if (priv->remove_attachment_banner) {
668 gtk_widget_destroy (priv->remove_attachment_banner);
669 g_object_unref (priv->remove_attachment_banner);
670 priv->remove_attachment_banner = NULL;
673 if (priv->purge_timeout > 0) {
674 g_source_remove (priv->purge_timeout);
675 priv->purge_timeout = 0;
678 if (priv->row_reference) {
679 gtk_tree_row_reference_free (priv->row_reference);
680 priv->row_reference = NULL;
683 if (priv->next_row_reference) {
684 gtk_tree_row_reference_free (priv->next_row_reference);
685 priv->next_row_reference = NULL;
689 g_free (priv->msg_uid);
690 priv->msg_uid = NULL;
693 G_OBJECT_CLASS(parent_class)->finalize (obj);
697 select_next_valid_row (GtkTreeModel *model,
698 GtkTreeRowReference **row_reference,
701 GtkTreeIter tmp_iter;
702 GtkTreePath *path, *next;
703 gboolean retval = FALSE;
705 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
707 path = gtk_tree_row_reference_get_path (*row_reference);
708 gtk_tree_model_get_iter (model, &tmp_iter, path);
709 gtk_tree_row_reference_free (*row_reference);
710 *row_reference = NULL;
712 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
713 next = gtk_tree_model_get_path (model, &tmp_iter);
714 *row_reference = gtk_tree_row_reference_new (model, next);
716 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
717 next = gtk_tree_model_get_path (model, &tmp_iter);
719 /* Ensure that we are not selecting the same */
720 if (gtk_tree_path_compare (path, next) != 0) {
721 *row_reference = gtk_tree_row_reference_new (model, next);
727 gtk_tree_path_free (path);
732 /* TODO: This should be in _init(), with the parameters as properties. */
734 modest_msg_view_window_construct (ModestMsgViewWindow *self,
735 const gchar *modest_account_name,
736 const gchar *msg_uid)
739 ModestMsgViewWindowPrivate *priv = NULL;
740 ModestWindowPrivate *parent_priv = NULL;
741 ModestDimmingRulesGroup *menu_rules_group = NULL;
742 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
743 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
745 obj = G_OBJECT (self);
746 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
747 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
749 priv->msg_uid = g_strdup (msg_uid);
752 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
753 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
754 gtk_widget_show (parent_priv->menubar);
755 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
757 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
758 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
759 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
761 /* Add common dimming rules */
762 modest_dimming_rules_group_add_rules (menu_rules_group,
763 modest_msg_view_menu_dimming_entries,
764 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
765 MODEST_WINDOW (self));
766 modest_dimming_rules_group_add_rules (toolbar_rules_group,
767 modest_msg_view_toolbar_dimming_entries,
768 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
769 MODEST_WINDOW (self));
770 modest_dimming_rules_group_add_rules (clipboard_rules_group,
771 modest_msg_view_clipboard_dimming_entries,
772 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
773 MODEST_WINDOW (self));
775 /* Insert dimming rules group for this window */
776 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
777 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
778 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
779 g_object_unref (menu_rules_group);
780 g_object_unref (toolbar_rules_group);
781 g_object_unref (clipboard_rules_group);
783 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
785 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
787 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
788 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
789 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
790 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
791 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
792 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
793 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
794 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
795 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
796 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
797 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
799 g_signal_connect (G_OBJECT (obj), "key-release-event",
800 G_CALLBACK (modest_msg_view_window_key_event),
803 g_signal_connect (G_OBJECT (obj), "key-press-event",
804 G_CALLBACK (modest_msg_view_window_key_event),
807 g_signal_connect (G_OBJECT (obj), "window-state-event",
808 G_CALLBACK (modest_msg_view_window_window_state_event),
811 g_signal_connect (G_OBJECT (obj), "move-focus",
812 G_CALLBACK (on_move_focus), obj);
814 /* Mail Operation Queue */
815 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
817 G_CALLBACK (on_queue_changed),
820 /* Account manager */
821 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
823 G_CALLBACK(on_account_removed),
826 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
828 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
829 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
830 priv->last_search = NULL;
832 /* Init the clipboard actions dim status */
833 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
835 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
837 /* Check toolbar dimming rules */
838 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
839 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
843 /* FIXME: parameter checks */
845 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
846 const gchar *modest_account_name,
847 const gchar *msg_uid,
849 GtkTreeRowReference *row_reference)
851 ModestMsgViewWindow *window = NULL;
852 ModestMsgViewWindowPrivate *priv = NULL;
853 TnyFolder *header_folder = NULL;
854 ModestHeaderView *header_view = NULL;
855 ModestWindow *main_window = NULL;
856 ModestWindowMgr *mgr = NULL;
858 mgr = modest_runtime_get_window_mgr ();
859 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
860 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
862 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
864 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
866 /* Remember the message list's TreeModel so we can detect changes
867 * and change the list selection when necessary: */
869 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
871 g_warning ("%s: BUG: no main window", __FUNCTION__);
875 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
876 MODEST_MAIN_WINDOW(main_window),
877 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
878 if (header_view != NULL){
879 header_folder = modest_header_view_get_folder(header_view);
880 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) == TNY_FOLDER_TYPE_OUTBOX);
881 g_assert(header_folder != NULL);
882 priv->header_folder_id = tny_folder_get_id(header_folder);
883 g_assert(priv->header_folder_id != NULL);
884 g_object_unref(header_folder);
887 priv->header_model = g_object_ref(model);
888 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
889 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
890 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
892 priv->row_changed_handler = g_signal_connect(
893 GTK_TREE_MODEL(model), "row-changed",
894 G_CALLBACK(modest_msg_view_window_on_row_changed),
896 priv->row_deleted_handler = g_signal_connect(
897 GTK_TREE_MODEL(model), "row-deleted",
898 G_CALLBACK(modest_msg_view_window_on_row_deleted),
900 priv->row_inserted_handler = g_signal_connect (
901 GTK_TREE_MODEL(model), "row-inserted",
902 G_CALLBACK(modest_msg_view_window_on_row_inserted),
904 priv->rows_reordered_handler = g_signal_connect(
905 GTK_TREE_MODEL(model), "rows-reordered",
906 G_CALLBACK(modest_msg_view_window_on_row_reordered),
909 if (header_view != NULL){
910 modest_header_view_add_observer(header_view,
911 MODEST_HEADER_VIEW_OBSERVER(window));
914 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
915 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
916 gtk_widget_show_all (GTK_WIDGET (window));
918 modest_msg_view_window_update_priority (window);
920 /* Check toolbar dimming rules */
921 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
923 return MODEST_WINDOW(window);
927 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
928 const gchar *modest_account_name,
929 const gchar *msg_uid)
931 ModestMsgViewWindow *window = NULL;
932 ModestMsgViewWindowPrivate *priv = NULL;
933 ModestWindowMgr *mgr = NULL;
935 mgr = modest_runtime_get_window_mgr ();
936 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
937 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
938 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
940 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
942 /* Remember that this is a search result,
943 * so we can disable some UI appropriately: */
944 priv->is_search_result = TRUE;
946 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
947 update_window_title (window);
949 return MODEST_WINDOW(window);
953 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
954 const gchar *modest_account_name,
955 const gchar *msg_uid)
958 ModestMsgViewWindowPrivate *priv;
959 ModestWindowMgr *mgr = NULL;
961 g_return_val_if_fail (msg, NULL);
962 mgr = modest_runtime_get_window_mgr ();
963 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
964 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
965 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
966 modest_account_name, msg_uid);
968 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
969 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
971 return MODEST_WINDOW(obj);
974 void modest_msg_view_window_on_row_changed(
975 GtkTreeModel *header_model,
978 ModestMsgViewWindow *window){
979 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
982 void modest_msg_view_window_on_row_deleted(
983 GtkTreeModel *header_model,
985 ModestMsgViewWindow *window){
986 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
989 /* On insertions we check if the folder still has the message we are
990 * showing or do not. If do not, we do nothing. Which means we are still
991 * not attached to any header folder and thus next/prev buttons are
992 * still dimmed. Once the message that is shown by msg-view is found, the
993 * new model of header-view will be attached and the references will be set.
994 * On each further insertions dimming rules will be checked. However
995 * this requires extra CPU time at least works.
996 * (An message might be deleted from TnyFolder and thus will not be
997 * inserted into the model again for example if it is removed by the
998 * imap server and the header view is refreshed.)
1000 void modest_msg_view_window_on_row_inserted(
1001 GtkTreeModel *new_model,
1002 GtkTreePath *tree_path,
1003 GtkTreeIter *tree_iter,
1004 ModestMsgViewWindow *window){
1005 ModestMsgViewWindowPrivate *priv = NULL;
1006 TnyHeader *header = NULL;
1009 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1011 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1013 /* If we already has a model attached then the message shown by
1014 * msg-view is in it, and thus we do not need any actions but
1015 * to check the dimming rules.*/
1016 if(priv->header_model != NULL){
1017 gtk_tree_row_reference_free(priv->next_row_reference);
1018 priv->next_row_reference = gtk_tree_row_reference_copy(
1019 priv->row_reference);
1020 select_next_valid_row (priv->header_model,
1021 &(priv->next_row_reference), FALSE);
1022 modest_ui_actions_check_toolbar_dimming_rules (
1023 MODEST_WINDOW (window));
1027 /* Check if the newly inserted message is the same we are actually
1028 * showing. IF not, we should remain detached from the header model
1029 * and thus prev and next toolbarbuttons should remain dimmed. */
1030 gtk_tree_model_get (new_model, tree_iter,
1031 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1032 uid = modest_tny_folder_get_header_unique_id(header);
1033 g_object_unref(G_OBJECT(header));
1035 if(!g_str_equal(priv->msg_uid, uid)){
1041 /* Setup row_reference for the actual msg. */
1042 priv->row_reference = gtk_tree_row_reference_new(
1043 new_model, tree_path);
1044 if(priv->row_reference == NULL){
1045 g_warning("No reference for msg header item.");
1049 /* Attach new_model and connect some callback to it to become able
1050 * to detect changes in header-view. */
1051 priv->header_model = g_object_ref(new_model);
1052 g_signal_connect (new_model, "row-changed",
1053 G_CALLBACK (modest_msg_view_window_on_row_changed),
1055 g_signal_connect (new_model, "row-deleted",
1056 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1058 g_signal_connect (new_model, "rows-reordered",
1059 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1062 /* Now set up next_row_reference. */
1063 priv->next_row_reference = gtk_tree_row_reference_copy(
1064 priv->row_reference);
1065 select_next_valid_row (priv->header_model,
1066 &(priv->next_row_reference), FALSE);
1068 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1071 void modest_msg_view_window_on_row_reordered(
1072 GtkTreeModel *header_model,
1076 ModestMsgViewWindow *window){
1077 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1080 /* The modest_msg_view_window_update_model_replaced implements update
1081 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1082 * actually belongs to the header-view is the same as the TnyFolder of
1083 * the message of msg-view or not. If they are different, there is
1084 * nothing to do. If they are the same, then the model has replaced and
1085 * the reference in msg-view shall be replaced from the old model to
1086 * the new model. In this case the view will be detached from it's
1087 * header folder. From this point the next/prev buttons are dimmed.
1089 void modest_msg_view_window_update_model_replaced(
1090 ModestHeaderViewObserver *observer,
1091 GtkTreeModel *model,
1092 const gchar *tny_folder_id){
1093 ModestMsgViewWindowPrivate *priv = NULL;
1094 ModestMsgViewWindow *window = NULL;
1096 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1097 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1099 window = MODEST_MSG_VIEW_WINDOW(observer);
1100 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1102 /* If there is an other folder in the header-view then we do
1103 * not care about it's model (msg list). Else if the
1104 * header-view shows the folder the msg shown by us is in, we
1105 * shall replace our model reference and make some check. */
1106 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1109 /* Model is changed(replaced), so we should forget the old
1110 * one. Because there might be other references and there
1111 * might be some change on the model even if we unreferenced
1112 * it, we need to disconnect our signals here. */
1113 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1114 priv->row_changed_handler))
1115 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1116 priv->row_changed_handler);
1117 priv->row_changed_handler = 0;
1118 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1119 priv->row_deleted_handler))
1120 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1121 priv->row_deleted_handler);
1122 priv->row_deleted_handler = 0;
1123 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1124 priv->row_inserted_handler))
1125 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1126 priv->row_inserted_handler);
1127 priv->row_inserted_handler = 0;
1128 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1129 priv->rows_reordered_handler))
1130 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1131 priv->rows_reordered_handler);
1132 priv->rows_reordered_handler = 0;
1133 g_object_unref(priv->header_model);
1134 priv->header_model = NULL;
1135 g_object_unref(priv->row_reference);
1136 priv->row_reference = NULL;
1137 g_object_unref(priv->next_row_reference);
1138 priv->next_row_reference = NULL;
1140 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1142 g_assert(model != NULL);
1144 /* Also we must connect to the new model for row insertions.
1145 * Only for insertions now. We will need other ones only after
1146 * the msg is show by msg-view is added to the new model. */
1147 priv->row_inserted_handler = g_signal_connect (
1148 model, "row-inserted",
1149 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1154 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1156 ModestMsgViewWindowPrivate *priv= NULL;
1158 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1159 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1161 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1165 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1167 ModestMsgViewWindowPrivate *priv= NULL;
1169 TnyHeader *header = NULL;
1170 GtkTreePath *path = NULL;
1173 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1174 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1176 /* If the message was not obtained from a treemodel,
1177 * for instance if it was opened directly by the search UI:
1179 if (priv->header_model == NULL) {
1180 msg = modest_msg_view_window_get_message (self);
1182 header = tny_msg_get_header (msg);
1183 g_object_unref (msg);
1188 /* Get iter of the currently selected message in the header view: */
1189 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1190 * instead of sometimes retrieving it from the header view?
1191 * Then we wouldn't be dependent on the message actually still being selected
1192 * in the header view. murrayc. */
1193 if (!gtk_tree_row_reference_valid (priv->row_reference))
1195 path = gtk_tree_row_reference_get_path (priv->row_reference);
1196 g_return_val_if_fail (path != NULL, NULL);
1197 gtk_tree_model_get_iter (priv->header_model,
1201 /* Get current message header */
1202 gtk_tree_model_get (priv->header_model, &iter,
1203 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1206 gtk_tree_path_free (path);
1211 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1213 ModestMsgViewWindowPrivate *priv;
1215 g_return_val_if_fail (self, NULL);
1217 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1219 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1223 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1225 ModestMsgViewWindowPrivate *priv;
1227 g_return_val_if_fail (self, NULL);
1229 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1231 return (const gchar*) priv->msg_uid;
1235 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1238 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1239 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1240 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1244 is_active = gtk_toggle_action_get_active (toggle);
1247 gtk_widget_show (priv->find_toolbar);
1248 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1250 gtk_widget_hide (priv->find_toolbar);
1253 /* update the toggle buttons status */
1254 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1255 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1256 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1257 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1262 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1263 ModestMsgViewWindow *obj)
1265 GtkToggleAction *toggle;
1266 ModestWindowPrivate *parent_priv;
1267 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1269 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1270 gtk_toggle_action_set_active (toggle, FALSE);
1274 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1275 ModestMsgViewWindow *obj)
1277 gchar *current_search;
1278 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1280 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1281 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1285 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1287 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1288 g_free (current_search);
1289 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1293 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1295 g_free (priv->last_search);
1296 priv->last_search = g_strdup (current_search);
1297 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1300 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1301 g_free (priv->last_search);
1302 priv->last_search = NULL;
1304 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1307 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1308 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1309 g_free (priv->last_search);
1310 priv->last_search = NULL;
1312 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1316 g_free (current_search);
1321 modest_msg_view_window_set_zoom (ModestWindow *window,
1324 ModestMsgViewWindowPrivate *priv;
1325 ModestWindowPrivate *parent_priv;
1326 GtkAction *action = NULL;
1327 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1329 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1331 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1332 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1333 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1335 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1336 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1338 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1342 modest_msg_view_window_get_zoom (ModestWindow *window)
1344 ModestMsgViewWindowPrivate *priv;
1346 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1348 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1349 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1353 modest_msg_view_window_zoom_plus (ModestWindow *window)
1355 ModestWindowPrivate *parent_priv;
1356 GtkRadioAction *zoom_radio_action;
1357 GSList *group, *node;
1359 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1360 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1361 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1363 group = gtk_radio_action_get_group (zoom_radio_action);
1365 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1366 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1370 for (node = group; node != NULL; node = g_slist_next (node)) {
1371 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1372 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1380 modest_msg_view_window_zoom_minus (ModestWindow *window)
1382 ModestWindowPrivate *parent_priv;
1383 GtkRadioAction *zoom_radio_action;
1384 GSList *group, *node;
1386 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1387 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1388 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1390 group = gtk_radio_action_get_group (zoom_radio_action);
1392 for (node = group; node != NULL; node = g_slist_next (node)) {
1393 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1394 if (node->next != NULL) {
1395 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1398 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1408 modest_msg_view_window_key_event (GtkWidget *window,
1413 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1414 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1415 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1416 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1417 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1418 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1419 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1420 gboolean return_value;
1422 if (event->type == GDK_KEY_RELEASE) {
1423 GtkScrollType scroll_type;
1425 switch (event->keyval) {
1428 scroll_type = GTK_SCROLL_STEP_UP; break;
1431 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1433 case GDK_KP_Page_Up:
1434 scroll_type = GTK_SCROLL_PAGE_UP; break;
1436 case GDK_KP_Page_Down:
1437 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1440 scroll_type = GTK_SCROLL_START; break;
1443 scroll_type = GTK_SCROLL_END; break;
1444 default: scroll_type = GTK_SCROLL_NONE;
1447 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1448 scroll_type, FALSE, &return_value);
1459 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1462 ModestMsgViewWindowPrivate *priv;
1463 GtkTreeIter tmp_iter;
1464 gboolean is_last_selected;
1466 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1467 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1469 /*if no model (so no rows at all), then virtually we are the last*/
1470 if (!priv->header_model)
1473 path = gtk_tree_row_reference_get_path (priv->row_reference);
1477 is_last_selected = TRUE;
1478 while (is_last_selected) {
1480 gtk_tree_path_next (path);
1481 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1483 gtk_tree_model_get (priv->header_model, &tmp_iter,
1484 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1487 if (msg_is_visible (header, priv->is_outbox))
1488 is_last_selected = FALSE;
1489 g_object_unref(G_OBJECT(header));
1492 gtk_tree_path_free (path);
1493 return is_last_selected;
1497 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1499 ModestMsgViewWindowPrivate *priv;
1501 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1502 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1504 return priv->header_model != NULL;
1508 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1510 ModestMsgViewWindowPrivate *priv;
1512 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1513 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1515 return priv->is_search_result;
1519 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1521 return (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) &&
1522 ( (!check_outbox) || (modest_tny_all_send_queues_get_msg_status (header) != MODEST_TNY_SEND_QUEUE_FAILED)) ;
1527 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1530 ModestMsgViewWindowPrivate *priv;
1531 gboolean is_first_selected;
1532 GtkTreeIter tmp_iter;
1533 /* gchar * path_string;*/
1535 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1536 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1538 /*if no model (so no rows at all), then virtually we are the first*/
1539 if (!priv->header_model)
1542 path = gtk_tree_row_reference_get_path (priv->row_reference);
1546 /* path_string = gtk_tree_path_to_string (path);
1547 is_first_selected = strcmp (path_string, "0");
1549 g_free (path_string);
1550 gtk_tree_path_free (path);
1552 return is_first_selected;*/
1554 is_first_selected = TRUE;
1555 while (is_first_selected) {
1557 if(!gtk_tree_path_prev (path))
1559 /* Here the 'if' is needless for logic, but let make sure
1560 * iter is valid for gtk_tree_model_get. */
1561 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1563 gtk_tree_model_get (priv->header_model, &tmp_iter,
1564 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1567 if (msg_is_visible (header, priv->is_outbox))
1568 is_first_selected = FALSE;
1569 g_object_unref(G_OBJECT(header));
1572 gtk_tree_path_free (path);
1573 return is_first_selected;
1577 * Reads the message whose summary item is @header. It takes care of
1578 * several things, among others:
1580 * If the message was not previously downloaded then ask the user
1581 * before downloading. If there is no connection launch the connection
1582 * dialog. Update toolbar dimming rules.
1584 * Returns: TRUE if the mail operation was started, otherwise if the
1585 * user do not want to download the message, or if the user do not
1586 * want to connect, then the operation is not issued
1589 message_reader (ModestMsgViewWindow *window,
1590 ModestMsgViewWindowPrivate *priv,
1592 GtkTreeRowReference *row_reference)
1594 ModestMailOperation *mail_op = NULL;
1595 gboolean already_showing = FALSE;
1596 ModestWindow *msg_window = NULL;
1597 ModestWindowMgr *mgr;
1599 g_return_val_if_fail (row_reference != NULL, FALSE);
1601 mgr = modest_runtime_get_window_mgr ();
1602 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1603 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1606 gtk_window_present (GTK_WINDOW (msg_window));
1607 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1611 /* Msg download completed */
1612 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1613 /* Ask the user if he wants to download the message if
1615 if (!tny_device_is_online (modest_runtime_get_device())) {
1616 TnyFolder *folder = NULL;
1617 GtkResponseType response;
1619 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1620 _("mcen_nc_get_msg"));
1621 if (response == GTK_RESPONSE_CANCEL)
1624 /* Offer the connection dialog if necessary */
1625 folder = tny_header_get_folder (header);
1627 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1628 TNY_FOLDER_STORE (folder))) {
1629 g_object_unref (folder);
1632 g_object_unref (folder);
1637 /* New mail operation */
1638 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1639 modest_ui_actions_get_msgs_full_error_handler,
1642 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1643 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1644 g_object_unref (mail_op);
1646 /* Update toolbar dimming rules */
1647 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1653 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1655 ModestMsgViewWindowPrivate *priv;
1656 GtkTreePath *path= NULL;
1657 GtkTreeIter tmp_iter;
1659 gboolean retval = TRUE;
1660 GtkTreeRowReference *row_reference = NULL;
1662 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1663 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1665 /* Update the next row reference if it's not valid. This could
1666 happen if for example the header which it was pointing to,
1667 was deleted. The best place to do it is in the row-deleted
1668 handler but the tinymail model do not work like the glib
1669 tree models and reports the deletion when the row is still
1671 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1672 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1673 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1674 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1677 if (priv->next_row_reference)
1678 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1682 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1684 gtk_tree_model_get_iter (priv->header_model,
1687 gtk_tree_path_free (path);
1689 gtk_tree_model_get (priv->header_model, &tmp_iter,
1690 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1693 /* Read the message & show it */
1694 if (!message_reader (window, priv, header, row_reference)) {
1696 gtk_tree_row_reference_free (row_reference);
1700 g_object_unref (header);
1706 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1708 ModestMsgViewWindowPrivate *priv = NULL;
1709 TnyHeader *header = NULL;
1711 GtkTreePath *path = NULL;
1712 GtkTreeRowReference *row_reference = NULL;
1714 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1715 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1717 /* Check that the model is not empty */
1718 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1721 /* Get the header */
1722 gtk_tree_model_get (priv->header_model,
1724 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1726 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1727 if (!msg_is_visible (header, priv->is_outbox)) {
1728 g_object_unref (header);
1729 return modest_msg_view_window_select_next_message (self);
1732 path = gtk_tree_model_get_path (priv->header_model, &iter);
1733 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1734 gtk_tree_path_free (path);
1736 /* Read the message & show it */
1737 message_reader (self, priv, header, row_reference);
1740 g_object_unref (header);
1746 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1748 ModestMsgViewWindowPrivate *priv = NULL;
1750 GtkTreeRowReference *row_reference = NULL;
1752 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1753 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1755 /* Return inmediatly if there is no header model */
1756 if (!priv->header_model)
1759 path = gtk_tree_row_reference_get_path (priv->row_reference);
1760 while (gtk_tree_path_prev (path)) {
1764 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1765 gtk_tree_model_get (priv->header_model, &iter,
1766 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1770 if (!msg_is_visible (header, priv->is_outbox)) {
1771 g_object_unref (header);
1775 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1776 /* Read the message & show it */
1777 if (!message_reader (window, priv, header, row_reference)) {
1778 gtk_tree_row_reference_free (row_reference);
1779 g_object_unref (header);
1783 gtk_tree_path_free (path);
1784 g_object_unref (header);
1789 gtk_tree_path_free (path);
1794 view_msg_cb (ModestMailOperation *mail_op,
1801 ModestMsgViewWindow *self = NULL;
1802 ModestMsgViewWindowPrivate *priv = NULL;
1803 GtkTreeRowReference *row_reference = NULL;
1805 /* If there was any error */
1806 row_reference = (GtkTreeRowReference *) user_data;
1807 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1808 gtk_tree_row_reference_free (row_reference);
1812 /* Get the window */
1813 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1814 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1815 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1817 /* Update the row reference */
1818 gtk_tree_row_reference_free (priv->row_reference);
1819 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1820 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1821 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1822 gtk_tree_row_reference_free (row_reference);
1824 /* Mark header as read */
1825 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1826 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1828 /* Set new message */
1829 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1830 modest_msg_view_window_update_priority (self);
1831 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1832 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1834 /* Set the new message uid of the window */
1835 if (priv->msg_uid) {
1836 g_free (priv->msg_uid);
1837 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1840 /* Notify the observers */
1841 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1842 0, priv->header_model, priv->row_reference);
1844 /* Free new references */
1845 g_object_unref (self);
1849 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1851 ModestMsgViewWindowPrivate *priv;
1853 TnyFolderType folder_type;
1855 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1857 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1859 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1863 folder = tny_msg_get_folder (msg);
1865 folder_type = tny_folder_get_folder_type (folder);
1866 g_object_unref (folder);
1868 g_object_unref (msg);
1876 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1878 ModestMsgViewWindowPrivate *priv;
1879 TnyHeaderFlags flags = 0;
1881 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1883 if (priv->header_model) {
1886 GtkTreePath *path = NULL;
1888 path = gtk_tree_row_reference_get_path (priv->row_reference);
1889 g_return_if_fail (path != NULL);
1890 gtk_tree_model_get_iter (priv->header_model,
1892 gtk_tree_row_reference_get_path (priv->row_reference));
1894 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1897 flags = tny_header_get_flags (header);
1898 g_object_unref(G_OBJECT(header));
1900 gtk_tree_path_free (path);
1903 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1908 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1910 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1911 ModestWindowPrivate *parent_priv;
1912 ModestWindowMgr *mgr;
1913 gboolean is_fullscreen;
1914 GtkAction *fs_toggle_action;
1917 mgr = modest_runtime_get_window_mgr ();
1918 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1920 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1922 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1923 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1924 if (is_fullscreen != active) {
1925 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1934 set_homogeneous (GtkWidget *widget,
1937 if (GTK_IS_TOOL_ITEM (widget)) {
1938 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1939 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1944 modest_msg_view_window_show_toolbar (ModestWindow *self,
1945 gboolean show_toolbar)
1947 ModestMsgViewWindowPrivate *priv = NULL;
1948 ModestWindowPrivate *parent_priv;
1949 GtkWidget *reply_button = NULL, *menu = NULL;
1950 GtkWidget *placeholder = NULL;
1952 const gchar *action_name;
1955 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1956 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1958 /* Set optimized view status */
1959 priv->optimized_view = !show_toolbar;
1961 if (!parent_priv->toolbar) {
1962 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1964 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1966 /* Set homogeneous toolbar */
1967 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1968 set_homogeneous, NULL);
1970 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1971 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1972 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1973 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1974 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1975 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1976 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1977 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1979 /* Add ProgressBar (Transfer toolbar) */
1980 priv->progress_bar = modest_progress_bar_widget_new ();
1981 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1982 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1983 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1984 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1985 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1987 /* Connect cancel 'clicked' signal to abort progress mode */
1988 g_signal_connect(priv->cancel_toolitem, "clicked",
1989 G_CALLBACK(cancel_progressbar),
1992 /* Add it to the observers list */
1993 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1996 hildon_window_add_toolbar (HILDON_WINDOW (self),
1997 GTK_TOOLBAR (parent_priv->toolbar));
1999 /* Set reply button tap and hold menu */
2000 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2001 "/ToolBar/ToolbarMessageReply");
2002 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2003 "/ToolbarReplyCSM");
2004 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2008 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2009 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2010 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2012 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2013 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2014 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2016 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2019 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2020 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2023 /* Update also the actions (to update the toggles in the
2024 menus), we have to do it manually because some other window
2025 of the same time could have changed it (remember that the
2026 toolbar fullscreen mode is shared by all the windows of the
2028 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2029 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2031 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2033 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2034 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2039 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2041 ModestMsgViewWindow *window)
2043 if (!GTK_WIDGET_VISIBLE (window))
2046 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2050 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2052 ModestMsgViewWindowPrivate *priv;
2054 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2055 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2057 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2061 cancel_progressbar (GtkToolButton *toolbutton,
2062 ModestMsgViewWindow *self)
2065 ModestMsgViewWindowPrivate *priv;
2067 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2069 /* Get operation observers and cancel its current operation */
2070 tmp = priv->progress_widgets;
2072 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2073 tmp=g_slist_next(tmp);
2077 observers_empty (ModestMsgViewWindow *self)
2080 ModestMsgViewWindowPrivate *priv;
2081 gboolean is_empty = TRUE;
2082 guint pending_ops = 0;
2084 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2085 tmp = priv->progress_widgets;
2087 /* Check all observers */
2088 while (tmp && is_empty) {
2089 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2090 is_empty = pending_ops == 0;
2092 tmp = g_slist_next(tmp);
2099 on_account_removed (TnyAccountStore *account_store,
2100 TnyAccount *account,
2103 /* Do nothing if it's a transport account, because we only
2104 show the messages of a store account */
2105 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2106 const gchar *parent_acc = NULL;
2107 const gchar *our_acc = NULL;
2109 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2110 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2112 /* Close this window if I'm showing a message of the removed account */
2113 if (strcmp (parent_acc, our_acc) == 0)
2114 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2119 on_mail_operation_started (ModestMailOperation *mail_op,
2122 ModestMsgViewWindow *self;
2123 ModestMailOperationTypeOperation op_type;
2125 ModestMsgViewWindowPrivate *priv;
2127 self = MODEST_MSG_VIEW_WINDOW (user_data);
2128 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2129 op_type = modest_mail_operation_get_type_operation (mail_op);
2130 tmp = priv->progress_widgets;
2132 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2133 set_toolbar_transfer_mode(self);
2135 modest_progress_object_add_operation (
2136 MODEST_PROGRESS_OBJECT (tmp->data),
2138 tmp = g_slist_next (tmp);
2144 on_mail_operation_finished (ModestMailOperation *mail_op,
2147 ModestMsgViewWindow *self;
2148 ModestMailOperationTypeOperation op_type;
2150 ModestMsgViewWindowPrivate *priv;
2152 self = MODEST_MSG_VIEW_WINDOW (user_data);
2153 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2154 op_type = modest_mail_operation_get_type_operation (mail_op);
2155 tmp = priv->progress_widgets;
2157 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2159 modest_progress_object_remove_operation (
2160 MODEST_PROGRESS_OBJECT (tmp->data),
2162 tmp = g_slist_next (tmp);
2165 /* If no more operations are being observed, NORMAL mode is enabled again */
2166 if (observers_empty (self)) {
2167 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2173 on_queue_changed (ModestMailOperationQueue *queue,
2174 ModestMailOperation *mail_op,
2175 ModestMailOperationQueueNotification type,
2176 ModestMsgViewWindow *self)
2178 ModestMsgViewWindowPrivate *priv;
2180 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2182 /* If this operations was created by another window, do nothing */
2183 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2186 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2187 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2189 "operation-started",
2190 G_CALLBACK (on_mail_operation_started),
2192 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2194 "operation-finished",
2195 G_CALLBACK (on_mail_operation_finished),
2197 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2198 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2200 "operation-started");
2201 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2203 "operation-finished");
2208 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2210 ModestMsgViewWindowPrivate *priv;
2211 GList *selected_attachments = NULL;
2213 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2214 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2216 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2218 return selected_attachments;
2222 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2224 ModestMsgViewWindowPrivate *priv;
2225 const gchar *msg_uid;
2226 gchar *attachment_uid = NULL;
2227 gint attachment_index = 0;
2230 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2231 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2232 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2234 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2235 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2236 attachment_index = g_list_index (attachments, mime_part);
2237 g_list_free (attachments);
2239 if (msg_uid && attachment_index >= 0) {
2240 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2243 if (mime_part == NULL) {
2244 gboolean error = FALSE;
2245 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2246 if (selected_attachments == NULL) {
2248 } else if (g_list_length (selected_attachments) > 1) {
2249 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2252 mime_part = (TnyMimePart *) selected_attachments->data;
2253 g_object_ref (mime_part);
2255 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2256 g_list_free (selected_attachments);
2261 g_object_ref (mime_part);
2264 if (tny_mime_part_is_purged (mime_part)) {
2265 g_object_unref (mime_part);
2269 if (!TNY_IS_MSG (mime_part)) {
2270 gchar *filepath = NULL;
2271 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2272 const gchar *content_type;
2273 TnyFsStream *temp_stream = NULL;
2274 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2277 if (temp_stream != NULL) {
2278 content_type = tny_mime_part_get_content_type (mime_part);
2279 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2281 /* make the file read-only */
2282 if (g_chmod(filepath, 0444) != 0)
2283 g_warning ("%s: failed to set file '%s' to read-only: %s",
2284 __FUNCTION__, filepath, strerror(errno));
2286 modest_platform_activate_file (filepath, content_type);
2287 g_object_unref (temp_stream);
2289 /* NOTE: files in the temporary area will be automatically
2290 * cleaned after some time if they are no longer in use */
2291 } else if (filepath != NULL) {
2292 /* the file may already exist but it isn't writable,
2293 * let's try to open it anyway */
2294 content_type = tny_mime_part_get_content_type (mime_part);
2295 modest_platform_activate_file (filepath, content_type);
2299 /* message attachment */
2300 TnyHeader *header = NULL;
2301 ModestWindowMgr *mgr;
2302 ModestWindow *msg_win = NULL;
2305 header = tny_msg_get_header (TNY_MSG (mime_part));
2306 mgr = modest_runtime_get_window_mgr ();
2307 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2310 if (msg_win) /* there is already a window for this uid; top it */
2311 gtk_window_present (GTK_WINDOW(msg_win));
2313 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2314 * thus, we don't do anything */
2315 g_warning ("window for is already being created");
2317 /* it's not found, so create a new window for it */
2318 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2319 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2321 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2322 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2323 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2324 modest_window_get_zoom (MODEST_WINDOW (window)));
2325 modest_window_mgr_register_window (mgr, msg_win);
2326 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2327 gtk_widget_show_all (GTK_WIDGET (msg_win));
2330 g_object_unref (mime_part);
2346 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2347 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2348 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2349 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2352 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2356 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2357 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2358 g_free (pair->filename);
2359 g_object_unref (pair->part);
2360 g_slice_free (SaveMimePartPair, pair);
2362 g_list_free (info->pairs);
2365 gtk_widget_destroy (info->banner);
2366 g_object_unref (info->banner);
2367 g_slice_free (SaveMimePartInfo, info);
2372 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2374 if (info->pairs != NULL) {
2375 save_mime_part_to_file (info);
2378 result = info->result;
2380 /* This is a GDK lock because we are an idle callback and
2381 * hildon_banner_show_information is or does Gtk+ code */
2383 gdk_threads_enter (); /* CHECKED */
2384 save_mime_part_info_free (info, TRUE);
2386 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2388 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2390 gdk_threads_leave (); /* CHECKED */
2397 save_mime_part_to_file (SaveMimePartInfo *info)
2399 GnomeVFSResult result;
2400 GnomeVFSHandle *handle;
2402 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2404 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2405 if (result == GNOME_VFS_OK) {
2406 stream = tny_vfs_stream_new (handle);
2407 tny_mime_part_decode_to_stream (pair->part, stream);
2408 g_object_unref (G_OBJECT (stream));
2409 g_object_unref (pair->part);
2410 g_slice_free (SaveMimePartPair, pair);
2411 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2412 info->result = TRUE;
2414 save_mime_part_info_free (info, FALSE);
2415 info->result = FALSE;
2418 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2423 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2425 gboolean is_ok = TRUE;
2426 gint replaced_files = 0;
2427 const GList *files = info->pairs;
2430 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2431 SaveMimePartPair *pair = iter->data;
2432 if (modest_utils_file_exists (pair->filename)) {
2436 if (replaced_files) {
2437 GtkWidget *confirm_overwrite_dialog;
2438 const gchar *message = (replaced_files == 1) ?
2439 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2440 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2441 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2444 gtk_widget_destroy (confirm_overwrite_dialog);
2448 save_mime_part_info_free (info, TRUE);
2450 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2451 _CS("sfil_ib_saving"));
2452 info->banner = g_object_ref (banner);
2453 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2454 g_object_unref (banner);
2461 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2463 gboolean clean_list = FALSE;
2464 ModestMsgViewWindowPrivate *priv;
2465 GList *files_to_save = NULL;
2466 GtkWidget *save_dialog = NULL;
2467 gchar *folder = NULL;
2468 gboolean canceled = FALSE;
2469 const gchar *filename = NULL;
2470 gchar *save_multiple_str = NULL;
2472 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2473 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2475 if (mime_parts == NULL) {
2476 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2477 if (mime_parts == NULL)
2482 /* prepare dialog */
2483 if (mime_parts->next == NULL) {
2484 /* only one attachment selected */
2485 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2486 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2487 filename = tny_mime_part_get_filename (mime_part);
2489 g_warning ("Tried to save a non-file attachment");
2493 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2494 g_list_length (mime_parts));
2497 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2498 GTK_FILE_CHOOSER_ACTION_SAVE);
2501 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2502 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2506 if (filename != NULL)
2507 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2510 /* if multiple, set multiple string */
2511 if (save_multiple_str) {
2512 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2516 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2517 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2519 if (!modest_utils_folder_writable (chooser_uri)) {
2520 hildon_banner_show_information
2521 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2525 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2526 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2528 if (tny_mime_part_is_attachment (mime_part)) {
2529 SaveMimePartPair *pair;
2531 if ((mime_parts->next != NULL) &&
2532 (tny_mime_part_get_filename (mime_part) == NULL))
2535 pair = g_slice_new0 (SaveMimePartPair);
2536 if (mime_parts->next == NULL) {
2537 pair->filename = g_strdup (chooser_uri);
2540 g_build_filename (chooser_uri,
2541 tny_mime_part_get_filename (mime_part), NULL);
2543 pair->part = g_object_ref (mime_part);
2544 files_to_save = g_list_prepend (files_to_save, pair);
2548 g_free (chooser_uri);
2551 gtk_widget_destroy (save_dialog);
2554 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2555 g_list_free (mime_parts);
2558 if (files_to_save != NULL) {
2559 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2560 info->pairs = files_to_save;
2561 info->result = TRUE;
2562 save_mime_parts_to_file_with_checks (info);
2567 show_remove_attachment_information (gpointer userdata)
2569 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2570 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2572 /* We're outside the main lock */
2573 gdk_threads_enter ();
2575 if (priv->remove_attachment_banner != NULL) {
2576 gtk_widget_destroy (priv->remove_attachment_banner);
2577 g_object_unref (priv->remove_attachment_banner);
2580 priv->remove_attachment_banner = g_object_ref (
2581 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2583 gdk_threads_leave ();
2589 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2591 ModestMsgViewWindowPrivate *priv;
2592 GList *mime_parts = NULL, *node;
2593 gchar *confirmation_message;
2597 /* TnyFolder *folder; */
2599 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2600 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2603 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2605 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2607 /* Remove already purged messages from mime parts list */
2609 while (node != NULL) {
2610 TnyMimePart *part = TNY_MIME_PART (node->data);
2611 if (tny_mime_part_is_purged (part)) {
2612 GList *deleted_node = node;
2613 node = g_list_next (node);
2614 g_object_unref (part);
2615 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2617 node = g_list_next (node);
2621 if (mime_parts == NULL)
2624 n_attachments = g_list_length (mime_parts);
2625 if (n_attachments == 1) {
2626 const gchar *filename;
2628 if (TNY_IS_MSG (mime_parts->data)) {
2630 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2631 filename = tny_header_get_subject (header);
2632 g_object_unref (header);
2633 if (filename == NULL)
2634 filename = _("mail_va_no_subject");
2636 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2638 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2640 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2641 "mcen_nc_purge_files_text",
2642 n_attachments), n_attachments);
2644 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2645 confirmation_message);
2646 g_free (confirmation_message);
2648 if (response != GTK_RESPONSE_OK)
2651 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2652 /* folder = tny_msg_get_folder (msg); */
2653 /* tny_msg_uncache_attachments (msg); */
2654 /* tny_folder_refresh (folder, NULL); */
2655 /* g_object_unref (folder); */
2657 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2658 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2659 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2662 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2663 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2664 tny_msg_rewrite_cache (msg);
2665 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2667 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2668 g_list_free (mime_parts);
2670 if (priv->purge_timeout > 0) {
2671 g_source_remove (priv->purge_timeout);
2672 priv->purge_timeout = 0;
2675 if (priv->remove_attachment_banner) {
2676 gtk_widget_destroy (priv->remove_attachment_banner);
2677 g_object_unref (priv->remove_attachment_banner);
2678 priv->remove_attachment_banner = NULL;
2686 update_window_title (ModestMsgViewWindow *window)
2688 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2690 TnyHeader *header = NULL;
2691 const gchar *subject = NULL;
2693 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2696 header = tny_msg_get_header (msg);
2697 subject = tny_header_get_subject (header);
2698 g_object_unref (msg);
2701 if ((subject == NULL)||(subject[0] == '\0'))
2702 subject = _("mail_va_no_subject");
2704 gtk_window_set_title (GTK_WINDOW (window), subject);
2708 static void on_move_focus (GtkWidget *widget,
2709 GtkDirectionType direction,
2712 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");