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 init_window (ModestMsgViewWindow *obj)
540 GtkWidget *main_vbox;
541 ModestMsgViewWindowPrivate *priv;
542 ModestWindowPrivate *parent_priv;
544 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
545 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
547 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
548 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
549 main_vbox = gtk_vbox_new (FALSE, 6);
551 #ifdef MODEST_USE_MOZEMBED
552 priv->main_scroll = priv->msg_view;
553 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
555 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
556 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
558 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
559 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
560 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
562 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
563 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
565 priv->find_toolbar = hildon_find_toolbar_new (NULL);
566 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
567 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
569 gtk_widget_show_all (GTK_WIDGET(main_vbox));
573 modest_msg_view_window_disconnect_signals (ModestWindow *self)
575 ModestMsgViewWindowPrivate *priv;
576 ModestHeaderView *header_view = NULL;
577 ModestWindow *main_window = NULL;
579 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
581 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
582 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
583 priv->clipboard_change_handler))
584 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
585 priv->clipboard_change_handler);
587 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
588 priv->queue_change_handler))
589 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
590 priv->queue_change_handler);
592 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
593 priv->account_removed_handler))
594 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
595 priv->account_removed_handler);
597 if (priv->header_model) {
598 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
599 priv->row_changed_handler))
600 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
601 priv->row_changed_handler);
603 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
604 priv->row_deleted_handler))
605 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
606 priv->row_deleted_handler);
608 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
609 priv->row_inserted_handler))
610 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
611 priv->row_inserted_handler);
613 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
614 priv->rows_reordered_handler))
615 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
616 priv->rows_reordered_handler);
619 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
620 priv->sighandlers = NULL;
622 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
623 FALSE); /* don't create */
627 header_view = MODEST_HEADER_VIEW(
628 modest_main_window_get_child_widget(
629 MODEST_MAIN_WINDOW(main_window),
630 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
631 if (header_view == NULL)
634 modest_header_view_remove_observer(header_view,
635 MODEST_HEADER_VIEW_OBSERVER(self));
639 modest_msg_view_window_finalize (GObject *obj)
641 ModestMsgViewWindowPrivate *priv;
643 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
645 /* Sanity check: shouldn't be needed, the window mgr should
646 call this function before */
647 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
649 if (priv->header_model != NULL) {
650 g_object_unref (priv->header_model);
651 priv->header_model = NULL;
654 if (priv->progress_bar_timeout > 0) {
655 g_source_remove (priv->progress_bar_timeout);
656 priv->progress_bar_timeout = 0;
659 if (priv->remove_attachment_banner) {
660 gtk_widget_destroy (priv->remove_attachment_banner);
661 g_object_unref (priv->remove_attachment_banner);
662 priv->remove_attachment_banner = NULL;
665 if (priv->purge_timeout > 0) {
666 g_source_remove (priv->purge_timeout);
667 priv->purge_timeout = 0;
670 if (priv->row_reference) {
671 gtk_tree_row_reference_free (priv->row_reference);
672 priv->row_reference = NULL;
675 if (priv->next_row_reference) {
676 gtk_tree_row_reference_free (priv->next_row_reference);
677 priv->next_row_reference = NULL;
681 g_free (priv->msg_uid);
682 priv->msg_uid = NULL;
685 G_OBJECT_CLASS(parent_class)->finalize (obj);
689 select_next_valid_row (GtkTreeModel *model,
690 GtkTreeRowReference **row_reference,
693 GtkTreeIter tmp_iter;
694 GtkTreePath *path, *next;
695 gboolean retval = FALSE;
697 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
699 path = gtk_tree_row_reference_get_path (*row_reference);
700 gtk_tree_model_get_iter (model, &tmp_iter, path);
701 gtk_tree_row_reference_free (*row_reference);
702 *row_reference = NULL;
704 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
705 next = gtk_tree_model_get_path (model, &tmp_iter);
706 *row_reference = gtk_tree_row_reference_new (model, next);
708 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
709 next = gtk_tree_model_get_path (model, &tmp_iter);
711 /* Ensure that we are not selecting the same */
712 if (gtk_tree_path_compare (path, next) != 0) {
713 *row_reference = gtk_tree_row_reference_new (model, next);
719 gtk_tree_path_free (path);
724 /* TODO: This should be in _init(), with the parameters as properties. */
726 modest_msg_view_window_construct (ModestMsgViewWindow *self,
727 const gchar *modest_account_name,
728 const gchar *msg_uid)
731 ModestMsgViewWindowPrivate *priv = NULL;
732 ModestWindowPrivate *parent_priv = NULL;
733 ModestDimmingRulesGroup *menu_rules_group = NULL;
734 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
735 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
737 obj = G_OBJECT (self);
738 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
739 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
741 priv->msg_uid = g_strdup (msg_uid);
744 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
745 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
746 gtk_widget_show (parent_priv->menubar);
747 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
749 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
750 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
751 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
753 /* Add common dimming rules */
754 modest_dimming_rules_group_add_rules (menu_rules_group,
755 modest_msg_view_menu_dimming_entries,
756 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
757 MODEST_WINDOW (self));
758 modest_dimming_rules_group_add_rules (toolbar_rules_group,
759 modest_msg_view_toolbar_dimming_entries,
760 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
761 MODEST_WINDOW (self));
762 modest_dimming_rules_group_add_rules (clipboard_rules_group,
763 modest_msg_view_clipboard_dimming_entries,
764 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
765 MODEST_WINDOW (self));
767 /* Insert dimming rules group for this window */
768 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
769 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
770 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
771 g_object_unref (menu_rules_group);
772 g_object_unref (toolbar_rules_group);
773 g_object_unref (clipboard_rules_group);
775 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
777 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
779 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);
780 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
781 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
782 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
783 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
784 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
785 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
786 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
787 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
788 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
789 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
791 g_signal_connect (G_OBJECT (obj), "key-release-event",
792 G_CALLBACK (modest_msg_view_window_key_event),
795 g_signal_connect (G_OBJECT (obj), "key-press-event",
796 G_CALLBACK (modest_msg_view_window_key_event),
799 g_signal_connect (G_OBJECT (obj), "window-state-event",
800 G_CALLBACK (modest_msg_view_window_window_state_event),
803 g_signal_connect (G_OBJECT (obj), "move-focus",
804 G_CALLBACK (on_move_focus), obj);
806 /* Mail Operation Queue */
807 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
809 G_CALLBACK (on_queue_changed),
812 /* Account manager */
813 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
815 G_CALLBACK(on_account_removed),
818 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
820 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
821 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
822 priv->last_search = NULL;
824 /* Init the clipboard actions dim status */
825 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
827 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
829 /* Check toolbar dimming rules */
830 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
831 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
835 /* FIXME: parameter checks */
837 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
838 const gchar *modest_account_name,
839 const gchar *msg_uid,
841 GtkTreeRowReference *row_reference)
843 ModestMsgViewWindow *window = NULL;
844 ModestMsgViewWindowPrivate *priv = NULL;
845 TnyFolder *header_folder = NULL;
846 ModestHeaderView *header_view = NULL;
847 ModestWindow *main_window = NULL;
848 ModestWindowMgr *mgr = NULL;
850 mgr = modest_runtime_get_window_mgr ();
851 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
852 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
854 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
856 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
858 /* Remember the message list's TreeModel so we can detect changes
859 * and change the list selection when necessary: */
861 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
863 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
864 MODEST_MAIN_WINDOW(main_window),
865 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
868 if (header_view != NULL){
869 header_folder = modest_header_view_get_folder(header_view);
870 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) == TNY_FOLDER_TYPE_OUTBOX);
871 g_assert(header_folder != NULL);
872 priv->header_folder_id = tny_folder_get_id(header_folder);
873 g_assert(priv->header_folder_id != NULL);
874 g_object_unref(header_folder);
877 priv->header_model = g_object_ref(model);
879 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
880 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
881 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
883 priv->row_reference = NULL;
884 priv->next_row_reference = NULL;
887 priv->row_changed_handler = g_signal_connect(
888 GTK_TREE_MODEL(model), "row-changed",
889 G_CALLBACK(modest_msg_view_window_on_row_changed),
891 priv->row_deleted_handler = g_signal_connect(
892 GTK_TREE_MODEL(model), "row-deleted",
893 G_CALLBACK(modest_msg_view_window_on_row_deleted),
895 priv->row_inserted_handler = g_signal_connect (
896 GTK_TREE_MODEL(model), "row-inserted",
897 G_CALLBACK(modest_msg_view_window_on_row_inserted),
899 priv->rows_reordered_handler = g_signal_connect(
900 GTK_TREE_MODEL(model), "rows-reordered",
901 G_CALLBACK(modest_msg_view_window_on_row_reordered),
904 if (header_view != NULL){
905 modest_header_view_add_observer(header_view,
906 MODEST_HEADER_VIEW_OBSERVER(window));
909 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
910 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
911 gtk_widget_show_all (GTK_WIDGET (window));
913 modest_msg_view_window_update_priority (window);
915 /* Check toolbar dimming rules */
916 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
918 return MODEST_WINDOW(window);
922 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
923 const gchar *modest_account_name,
924 const gchar *msg_uid)
926 ModestMsgViewWindow *window = NULL;
927 ModestMsgViewWindowPrivate *priv = NULL;
928 ModestWindowMgr *mgr = NULL;
930 mgr = modest_runtime_get_window_mgr ();
931 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
932 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
933 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
935 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
937 /* Remember that this is a search result,
938 * so we can disable some UI appropriately: */
939 priv->is_search_result = TRUE;
941 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
943 update_window_title (window);
944 modest_msg_view_window_update_priority (window);
946 return MODEST_WINDOW(window);
950 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
951 const gchar *modest_account_name,
952 const gchar *msg_uid)
955 ModestMsgViewWindowPrivate *priv;
956 ModestWindowMgr *mgr = NULL;
958 g_return_val_if_fail (msg, NULL);
959 mgr = modest_runtime_get_window_mgr ();
960 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
961 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
962 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
963 modest_account_name, msg_uid);
965 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
966 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
968 return MODEST_WINDOW(obj);
971 void modest_msg_view_window_on_row_changed(
972 GtkTreeModel *header_model,
975 ModestMsgViewWindow *window){
976 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
979 void modest_msg_view_window_on_row_deleted(
980 GtkTreeModel *header_model,
982 ModestMsgViewWindow *window){
983 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
986 /* On insertions we check if the folder still has the message we are
987 * showing or do not. If do not, we do nothing. Which means we are still
988 * not attached to any header folder and thus next/prev buttons are
989 * still dimmed. Once the message that is shown by msg-view is found, the
990 * new model of header-view will be attached and the references will be set.
991 * On each further insertions dimming rules will be checked. However
992 * this requires extra CPU time at least works.
993 * (An message might be deleted from TnyFolder and thus will not be
994 * inserted into the model again for example if it is removed by the
995 * imap server and the header view is refreshed.)
997 void modest_msg_view_window_on_row_inserted(
998 GtkTreeModel *new_model,
999 GtkTreePath *tree_path,
1000 GtkTreeIter *tree_iter,
1001 ModestMsgViewWindow *window){
1002 ModestMsgViewWindowPrivate *priv = NULL;
1003 TnyHeader *header = NULL;
1006 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1008 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1010 /* If we already has a model attached then the message shown by
1011 * msg-view is in it, and thus we do not need any actions but
1012 * to check the dimming rules.*/
1013 if(priv->header_model != NULL){
1014 if (priv->row_reference) {
1015 gtk_tree_row_reference_free(priv->next_row_reference);
1016 priv->next_row_reference = gtk_tree_row_reference_copy(
1017 priv->row_reference);
1018 select_next_valid_row (priv->header_model,
1019 &(priv->next_row_reference), FALSE);
1021 modest_ui_actions_check_toolbar_dimming_rules (
1022 MODEST_WINDOW (window));
1026 /* Check if the newly inserted message is the same we are actually
1027 * showing. IF not, we should remain detached from the header model
1028 * and thus prev and next toolbarbuttons should remain dimmed. */
1029 gtk_tree_model_get (new_model, tree_iter,
1030 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1031 uid = modest_tny_folder_get_header_unique_id(header);
1032 if(!g_str_equal(priv->msg_uid, uid)){
1034 g_object_unref(G_OBJECT(header));
1038 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1039 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1040 g_object_unref(G_OBJECT(header));
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 if (priv->row_reference)
1139 g_object_unref(priv->row_reference);
1140 priv->row_reference = NULL;
1141 if (priv->next_row_reference)
1142 g_object_unref(priv->next_row_reference);
1143 priv->next_row_reference = NULL;
1145 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1147 g_assert(model != NULL);
1149 /* Also we must connect to the new model for row insertions.
1150 * Only for insertions now. We will need other ones only after
1151 * the msg is show by msg-view is added to the new model. */
1152 priv->row_inserted_handler = g_signal_connect (
1153 model, "row-inserted",
1154 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1159 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1161 ModestMsgViewWindowPrivate *priv= NULL;
1163 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1164 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1166 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1170 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1172 ModestMsgViewWindowPrivate *priv= NULL;
1174 TnyHeader *header = NULL;
1175 GtkTreePath *path = NULL;
1178 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1179 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1181 /* If the message was not obtained from a treemodel,
1182 * for instance if it was opened directly by the search UI:
1184 if (priv->header_model == NULL || priv->row_reference == NULL) {
1185 msg = modest_msg_view_window_get_message (self);
1187 header = tny_msg_get_header (msg);
1188 g_object_unref (msg);
1193 /* Get iter of the currently selected message in the header view: */
1194 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1195 * instead of sometimes retrieving it from the header view?
1196 * Then we wouldn't be dependent on the message actually still being selected
1197 * in the header view. murrayc. */
1198 if (!gtk_tree_row_reference_valid (priv->row_reference))
1200 path = gtk_tree_row_reference_get_path (priv->row_reference);
1201 g_return_val_if_fail (path != NULL, NULL);
1202 gtk_tree_model_get_iter (priv->header_model,
1206 /* Get current message header */
1207 gtk_tree_model_get (priv->header_model, &iter,
1208 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1211 gtk_tree_path_free (path);
1216 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1218 ModestMsgViewWindowPrivate *priv;
1220 g_return_val_if_fail (self, NULL);
1222 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1224 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1228 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1230 ModestMsgViewWindowPrivate *priv;
1232 g_return_val_if_fail (self, NULL);
1234 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1236 return (const gchar*) priv->msg_uid;
1240 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1243 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1244 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1245 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1249 is_active = gtk_toggle_action_get_active (toggle);
1252 gtk_widget_show (priv->find_toolbar);
1253 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1255 gtk_widget_hide (priv->find_toolbar);
1258 /* update the toggle buttons status */
1259 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1260 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1261 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1262 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1267 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1268 ModestMsgViewWindow *obj)
1270 GtkToggleAction *toggle;
1271 ModestWindowPrivate *parent_priv;
1272 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1274 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1275 gtk_toggle_action_set_active (toggle, FALSE);
1279 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1280 ModestMsgViewWindow *obj)
1282 gchar *current_search;
1283 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1285 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1286 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1290 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1292 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1293 g_free (current_search);
1294 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1298 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1300 g_free (priv->last_search);
1301 priv->last_search = g_strdup (current_search);
1302 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1305 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1306 g_free (priv->last_search);
1307 priv->last_search = NULL;
1309 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1312 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1313 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1314 g_free (priv->last_search);
1315 priv->last_search = NULL;
1317 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1321 g_free (current_search);
1326 modest_msg_view_window_set_zoom (ModestWindow *window,
1329 ModestMsgViewWindowPrivate *priv;
1330 ModestWindowPrivate *parent_priv;
1331 GtkAction *action = NULL;
1332 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1334 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1336 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1337 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1338 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1340 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1341 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1343 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1347 modest_msg_view_window_get_zoom (ModestWindow *window)
1349 ModestMsgViewWindowPrivate *priv;
1351 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1353 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1354 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1358 modest_msg_view_window_zoom_plus (ModestWindow *window)
1360 ModestWindowPrivate *parent_priv;
1361 GtkRadioAction *zoom_radio_action;
1362 GSList *group, *node;
1364 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1365 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1366 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1368 group = gtk_radio_action_get_group (zoom_radio_action);
1370 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1371 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1375 for (node = group; node != NULL; node = g_slist_next (node)) {
1376 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1377 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1385 modest_msg_view_window_zoom_minus (ModestWindow *window)
1387 ModestWindowPrivate *parent_priv;
1388 GtkRadioAction *zoom_radio_action;
1389 GSList *group, *node;
1391 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1392 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1393 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1395 group = gtk_radio_action_get_group (zoom_radio_action);
1397 for (node = group; node != NULL; node = g_slist_next (node)) {
1398 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1399 if (node->next != NULL) {
1400 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1403 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1413 modest_msg_view_window_key_event (GtkWidget *window,
1418 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1419 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1420 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1421 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1422 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1423 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1424 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1425 gboolean return_value;
1427 if (event->type == GDK_KEY_RELEASE) {
1428 GtkScrollType scroll_type;
1430 switch (event->keyval) {
1433 scroll_type = GTK_SCROLL_STEP_UP; break;
1436 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1438 case GDK_KP_Page_Up:
1439 scroll_type = GTK_SCROLL_PAGE_UP; break;
1441 case GDK_KP_Page_Down:
1442 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1445 scroll_type = GTK_SCROLL_START; break;
1448 scroll_type = GTK_SCROLL_END; break;
1449 default: scroll_type = GTK_SCROLL_NONE;
1452 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1453 scroll_type, FALSE, &return_value);
1464 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1467 ModestMsgViewWindowPrivate *priv;
1468 GtkTreeIter tmp_iter;
1469 gboolean is_last_selected;
1471 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1472 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1474 /*if no model (so no rows at all), then virtually we are the last*/
1475 if (!priv->header_model || !priv->row_reference)
1478 path = gtk_tree_row_reference_get_path (priv->row_reference);
1482 is_last_selected = TRUE;
1483 while (is_last_selected) {
1485 gtk_tree_path_next (path);
1486 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1488 gtk_tree_model_get (priv->header_model, &tmp_iter,
1489 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1492 if (msg_is_visible (header, priv->is_outbox))
1493 is_last_selected = FALSE;
1494 g_object_unref(G_OBJECT(header));
1497 gtk_tree_path_free (path);
1498 return is_last_selected;
1502 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1504 ModestMsgViewWindowPrivate *priv;
1506 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1507 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1509 return priv->header_model != NULL;
1513 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1515 ModestMsgViewWindowPrivate *priv;
1517 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1518 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1520 return priv->is_search_result;
1524 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1526 return (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) &&
1527 ( (!check_outbox) || (modest_tny_all_send_queues_get_msg_status (header) != MODEST_TNY_SEND_QUEUE_FAILED)) ;
1532 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1535 ModestMsgViewWindowPrivate *priv;
1536 gboolean is_first_selected;
1537 GtkTreeIter tmp_iter;
1538 /* gchar * path_string;*/
1540 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1541 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1543 /*if no model (so no rows at all), then virtually we are the first*/
1544 if (!priv->header_model || !priv->row_reference)
1547 path = gtk_tree_row_reference_get_path (priv->row_reference);
1551 /* path_string = gtk_tree_path_to_string (path);
1552 is_first_selected = strcmp (path_string, "0");
1554 g_free (path_string);
1555 gtk_tree_path_free (path);
1557 return is_first_selected;*/
1559 is_first_selected = TRUE;
1560 while (is_first_selected) {
1562 if(!gtk_tree_path_prev (path))
1564 /* Here the 'if' is needless for logic, but let make sure
1565 * iter is valid for gtk_tree_model_get. */
1566 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1568 gtk_tree_model_get (priv->header_model, &tmp_iter,
1569 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1572 if (msg_is_visible (header, priv->is_outbox))
1573 is_first_selected = FALSE;
1574 g_object_unref(G_OBJECT(header));
1577 gtk_tree_path_free (path);
1578 return is_first_selected;
1582 * Reads the message whose summary item is @header. It takes care of
1583 * several things, among others:
1585 * If the message was not previously downloaded then ask the user
1586 * before downloading. If there is no connection launch the connection
1587 * dialog. Update toolbar dimming rules.
1589 * Returns: TRUE if the mail operation was started, otherwise if the
1590 * user do not want to download the message, or if the user do not
1591 * want to connect, then the operation is not issued
1594 message_reader (ModestMsgViewWindow *window,
1595 ModestMsgViewWindowPrivate *priv,
1597 GtkTreeRowReference *row_reference)
1599 ModestMailOperation *mail_op = NULL;
1600 gboolean already_showing = FALSE;
1601 ModestWindow *msg_window = NULL;
1602 ModestWindowMgr *mgr;
1604 g_return_val_if_fail (row_reference != NULL, FALSE);
1606 mgr = modest_runtime_get_window_mgr ();
1607 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1608 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1611 gtk_window_present (GTK_WINDOW (msg_window));
1612 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1616 /* Msg download completed */
1617 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1618 /* Ask the user if he wants to download the message if
1620 if (!tny_device_is_online (modest_runtime_get_device())) {
1621 TnyFolder *folder = NULL;
1622 GtkResponseType response;
1624 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1625 _("mcen_nc_get_msg"));
1626 if (response == GTK_RESPONSE_CANCEL)
1629 /* Offer the connection dialog if necessary */
1630 folder = tny_header_get_folder (header);
1632 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1633 TNY_FOLDER_STORE (folder))) {
1634 g_object_unref (folder);
1637 g_object_unref (folder);
1642 /* New mail operation */
1643 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1644 modest_ui_actions_get_msgs_full_error_handler,
1647 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1648 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1649 g_object_unref (mail_op);
1651 /* Update toolbar dimming rules */
1652 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1658 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1660 ModestMsgViewWindowPrivate *priv;
1661 GtkTreePath *path= NULL;
1662 GtkTreeIter tmp_iter;
1664 gboolean retval = TRUE;
1665 GtkTreeRowReference *row_reference = NULL;
1667 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1668 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1670 if (!priv->row_reference)
1673 /* Update the next row reference if it's not valid. This could
1674 happen if for example the header which it was pointing to,
1675 was deleted. The best place to do it is in the row-deleted
1676 handler but the tinymail model do not work like the glib
1677 tree models and reports the deletion when the row is still
1679 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1680 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1681 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1682 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1685 if (priv->next_row_reference)
1686 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1690 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1692 gtk_tree_model_get_iter (priv->header_model,
1695 gtk_tree_path_free (path);
1697 gtk_tree_model_get (priv->header_model, &tmp_iter,
1698 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1701 /* Read the message & show it */
1702 if (!message_reader (window, priv, header, row_reference)) {
1704 gtk_tree_row_reference_free (row_reference);
1708 g_object_unref (header);
1714 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1716 ModestMsgViewWindowPrivate *priv = NULL;
1717 TnyHeader *header = NULL;
1719 GtkTreePath *path = NULL;
1720 GtkTreeRowReference *row_reference = NULL;
1722 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1723 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1725 /* Check that the model is not empty */
1726 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1729 /* Get the header */
1730 gtk_tree_model_get (priv->header_model,
1732 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1734 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1735 if (!msg_is_visible (header, priv->is_outbox)) {
1736 g_object_unref (header);
1737 return modest_msg_view_window_select_next_message (self);
1740 path = gtk_tree_model_get_path (priv->header_model, &iter);
1741 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1742 gtk_tree_path_free (path);
1744 /* Read the message & show it */
1745 message_reader (self, priv, header, row_reference);
1748 g_object_unref (header);
1754 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1756 ModestMsgViewWindowPrivate *priv = NULL;
1758 GtkTreeRowReference *row_reference = NULL;
1760 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1761 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1763 /* Return inmediatly if there is no header model */
1764 if (!priv->header_model || !priv->row_reference)
1767 path = gtk_tree_row_reference_get_path (priv->row_reference);
1768 while (gtk_tree_path_prev (path)) {
1772 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1773 gtk_tree_model_get (priv->header_model, &iter,
1774 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1778 if (!msg_is_visible (header, priv->is_outbox)) {
1779 g_object_unref (header);
1783 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1784 /* Read the message & show it */
1785 if (!message_reader (window, priv, header, row_reference)) {
1786 gtk_tree_row_reference_free (row_reference);
1787 g_object_unref (header);
1791 gtk_tree_path_free (path);
1792 g_object_unref (header);
1797 gtk_tree_path_free (path);
1802 view_msg_cb (ModestMailOperation *mail_op,
1809 ModestMsgViewWindow *self = NULL;
1810 ModestMsgViewWindowPrivate *priv = NULL;
1811 GtkTreeRowReference *row_reference = NULL;
1814 g_object_unref (self);
1818 /* If there was any error */
1819 row_reference = (GtkTreeRowReference *) user_data;
1820 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1821 gtk_tree_row_reference_free (row_reference);
1825 /* Get the window */
1826 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1827 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1828 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1830 /* Update the row reference */
1831 if (priv->row_reference != NULL) {
1832 gtk_tree_row_reference_free (priv->row_reference);
1833 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1834 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1835 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1836 gtk_tree_row_reference_free (row_reference);
1839 /* Mark header as read */
1840 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1841 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1843 /* Set new message */
1844 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
1845 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1846 modest_msg_view_window_update_priority (self);
1847 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1848 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1851 /* Set the new message uid of the window */
1852 if (priv->msg_uid) {
1853 g_free (priv->msg_uid);
1854 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1857 /* Notify the observers */
1858 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1859 0, priv->header_model, priv->row_reference);
1861 /* Free new references */
1862 g_object_unref (self);
1866 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1868 ModestMsgViewWindowPrivate *priv;
1870 TnyFolderType folder_type;
1872 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1874 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1876 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1880 folder = tny_msg_get_folder (msg);
1882 folder_type = tny_folder_get_folder_type (folder);
1883 g_object_unref (folder);
1885 g_object_unref (msg);
1893 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1895 ModestMsgViewWindowPrivate *priv;
1896 TnyHeader *header = NULL;
1897 TnyHeaderFlags flags = 0;
1899 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1901 if (priv->header_model && priv->row_reference) {
1903 GtkTreePath *path = NULL;
1905 path = gtk_tree_row_reference_get_path (priv->row_reference);
1906 g_return_if_fail (path != NULL);
1907 gtk_tree_model_get_iter (priv->header_model,
1909 gtk_tree_row_reference_get_path (priv->row_reference));
1911 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1913 gtk_tree_path_free (path);
1916 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1918 header = tny_msg_get_header (msg);
1919 g_object_unref (msg);
1924 flags = tny_header_get_flags (header);
1925 g_object_unref(G_OBJECT(header));
1928 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1933 toolbar_resize (ModestMsgViewWindow *self)
1935 ModestMsgViewWindowPrivate *priv = NULL;
1936 ModestWindowPrivate *parent_priv = NULL;
1938 gint static_button_size;
1939 ModestWindowMgr *mgr;
1941 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1942 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1943 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1945 mgr = modest_runtime_get_window_mgr ();
1946 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1948 if (parent_priv->toolbar) {
1949 /* left size buttons */
1950 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1951 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1952 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1953 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1954 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
1955 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1956 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1957 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1958 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1959 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1960 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1961 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1962 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1963 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1964 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1965 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1967 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1968 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1969 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1970 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1971 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
1972 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
1973 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
1974 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
1980 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1982 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1983 ModestWindowPrivate *parent_priv;
1984 ModestWindowMgr *mgr;
1985 gboolean is_fullscreen;
1986 GtkAction *fs_toggle_action;
1989 mgr = modest_runtime_get_window_mgr ();
1990 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1992 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1994 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1995 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1996 if (is_fullscreen != active) {
1997 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1999 toolbar_resize (MODEST_MSG_VIEW_WINDOW (widget));
2007 modest_msg_view_window_show_toolbar (ModestWindow *self,
2008 gboolean show_toolbar)
2010 ModestMsgViewWindowPrivate *priv = NULL;
2011 ModestWindowPrivate *parent_priv;
2012 GtkWidget *reply_button = NULL, *menu = NULL;
2013 GtkWidget *placeholder = NULL;
2015 const gchar *action_name;
2018 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2019 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2021 /* Set optimized view status */
2022 priv->optimized_view = !show_toolbar;
2024 if (!parent_priv->toolbar) {
2025 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2027 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2029 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
2030 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2031 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2032 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2033 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2035 /* Add ProgressBar (Transfer toolbar) */
2036 priv->progress_bar = modest_progress_bar_widget_new ();
2037 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
2038 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
2039 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
2040 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
2041 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
2043 /* Connect cancel 'clicked' signal to abort progress mode */
2044 g_signal_connect(priv->cancel_toolitem, "clicked",
2045 G_CALLBACK(cancel_progressbar),
2048 /* Add it to the observers list */
2049 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
2052 hildon_window_add_toolbar (HILDON_WINDOW (self),
2053 GTK_TOOLBAR (parent_priv->toolbar));
2055 /* Set reply button tap and hold menu */
2056 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2057 "/ToolBar/ToolbarMessageReply");
2058 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2059 "/ToolbarReplyCSM");
2060 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2064 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2065 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2066 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2068 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2069 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2070 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2072 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2075 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2076 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2079 /* Update also the actions (to update the toggles in the
2080 menus), we have to do it manually because some other window
2081 of the same time could have changed it (remember that the
2082 toolbar fullscreen mode is shared by all the windows of the
2084 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2085 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2087 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2089 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2090 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2095 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2097 ModestMsgViewWindow *window)
2099 if (!GTK_WIDGET_VISIBLE (window))
2102 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2106 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2108 ModestMsgViewWindowPrivate *priv;
2110 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2111 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2113 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2117 cancel_progressbar (GtkToolButton *toolbutton,
2118 ModestMsgViewWindow *self)
2121 ModestMsgViewWindowPrivate *priv;
2123 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2125 /* Get operation observers and cancel its current operation */
2126 tmp = priv->progress_widgets;
2128 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2129 tmp=g_slist_next(tmp);
2133 observers_empty (ModestMsgViewWindow *self)
2136 ModestMsgViewWindowPrivate *priv;
2137 gboolean is_empty = TRUE;
2138 guint pending_ops = 0;
2140 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2141 tmp = priv->progress_widgets;
2143 /* Check all observers */
2144 while (tmp && is_empty) {
2145 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2146 is_empty = pending_ops == 0;
2148 tmp = g_slist_next(tmp);
2155 on_account_removed (TnyAccountStore *account_store,
2156 TnyAccount *account,
2159 /* Do nothing if it's a transport account, because we only
2160 show the messages of a store account */
2161 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2162 const gchar *parent_acc = NULL;
2163 const gchar *our_acc = NULL;
2165 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2166 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2168 /* Close this window if I'm showing a message of the removed account */
2169 if (strcmp (parent_acc, our_acc) == 0)
2170 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2175 on_mail_operation_started (ModestMailOperation *mail_op,
2178 ModestMsgViewWindow *self;
2179 ModestMailOperationTypeOperation op_type;
2181 ModestMsgViewWindowPrivate *priv;
2182 GObject *source = NULL;
2184 self = MODEST_MSG_VIEW_WINDOW (user_data);
2185 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2186 op_type = modest_mail_operation_get_type_operation (mail_op);
2187 tmp = priv->progress_widgets;
2188 source = modest_mail_operation_get_source(mail_op);
2189 if (G_OBJECT (self) == source) {
2190 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2191 set_toolbar_transfer_mode(self);
2193 modest_progress_object_add_operation (
2194 MODEST_PROGRESS_OBJECT (tmp->data),
2196 tmp = g_slist_next (tmp);
2200 g_object_unref (source);
2204 on_mail_operation_finished (ModestMailOperation *mail_op,
2207 ModestMsgViewWindow *self;
2208 ModestMailOperationTypeOperation op_type;
2210 ModestMsgViewWindowPrivate *priv;
2212 self = MODEST_MSG_VIEW_WINDOW (user_data);
2213 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2214 op_type = modest_mail_operation_get_type_operation (mail_op);
2215 tmp = priv->progress_widgets;
2217 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2219 modest_progress_object_remove_operation (
2220 MODEST_PROGRESS_OBJECT (tmp->data),
2222 tmp = g_slist_next (tmp);
2225 /* If no more operations are being observed, NORMAL mode is enabled again */
2226 if (observers_empty (self)) {
2227 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2233 on_queue_changed (ModestMailOperationQueue *queue,
2234 ModestMailOperation *mail_op,
2235 ModestMailOperationQueueNotification type,
2236 ModestMsgViewWindow *self)
2238 ModestMsgViewWindowPrivate *priv;
2240 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2242 /* If this operations was created by another window, do nothing */
2243 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2246 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2247 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2249 "operation-started",
2250 G_CALLBACK (on_mail_operation_started),
2252 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2254 "operation-finished",
2255 G_CALLBACK (on_mail_operation_finished),
2257 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2258 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2260 "operation-started");
2261 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2263 "operation-finished");
2268 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2270 ModestMsgViewWindowPrivate *priv;
2271 GList *selected_attachments = NULL;
2273 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2274 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2276 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2278 return selected_attachments;
2282 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2284 ModestMsgViewWindowPrivate *priv;
2285 const gchar *msg_uid;
2286 gchar *attachment_uid = NULL;
2287 gint attachment_index = 0;
2290 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2291 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2292 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2294 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2295 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2296 attachment_index = g_list_index (attachments, mime_part);
2297 g_list_free (attachments);
2299 if (msg_uid && attachment_index >= 0) {
2300 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2303 if (mime_part == NULL) {
2304 gboolean error = FALSE;
2305 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2306 if (selected_attachments == NULL) {
2308 } else if (g_list_length (selected_attachments) > 1) {
2309 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2312 mime_part = (TnyMimePart *) selected_attachments->data;
2313 g_object_ref (mime_part);
2315 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2316 g_list_free (selected_attachments);
2321 g_object_ref (mime_part);
2324 if (tny_mime_part_is_purged (mime_part)) {
2325 g_object_unref (mime_part);
2329 if (!TNY_IS_MSG (mime_part)) {
2330 gchar *filepath = NULL;
2331 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2332 const gchar *content_type;
2333 TnyFsStream *temp_stream = NULL;
2334 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2337 if (temp_stream != NULL) {
2338 content_type = tny_mime_part_get_content_type (mime_part);
2339 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2341 /* make the file read-only */
2342 if (g_chmod(filepath, 0444) != 0)
2343 g_warning ("%s: failed to set file '%s' to read-only: %s",
2344 __FUNCTION__, filepath, strerror(errno));
2346 modest_platform_activate_file (filepath, content_type);
2347 g_object_unref (temp_stream);
2349 /* NOTE: files in the temporary area will be automatically
2350 * cleaned after some time if they are no longer in use */
2351 } else if (filepath != NULL) {
2352 /* the file may already exist but it isn't writable,
2353 * let's try to open it anyway */
2354 content_type = tny_mime_part_get_content_type (mime_part);
2355 modest_platform_activate_file (filepath, content_type);
2359 /* message attachment */
2360 TnyHeader *header = NULL;
2361 ModestWindowMgr *mgr;
2362 ModestWindow *msg_win = NULL;
2365 header = tny_msg_get_header (TNY_MSG (mime_part));
2366 mgr = modest_runtime_get_window_mgr ();
2367 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2370 if (msg_win) /* there is already a window for this uid; top it */
2371 gtk_window_present (GTK_WINDOW(msg_win));
2373 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2374 * thus, we don't do anything */
2375 g_warning ("window for is already being created");
2377 /* it's not found, so create a new window for it */
2378 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2379 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2381 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2382 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2383 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2384 modest_window_get_zoom (MODEST_WINDOW (window)));
2385 modest_window_mgr_register_window (mgr, msg_win);
2386 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2387 gtk_widget_show_all (GTK_WIDGET (msg_win));
2390 g_object_unref (mime_part);
2406 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2407 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2408 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2409 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2412 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2416 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2417 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2418 g_free (pair->filename);
2419 g_object_unref (pair->part);
2420 g_slice_free (SaveMimePartPair, pair);
2422 g_list_free (info->pairs);
2425 gtk_widget_destroy (info->banner);
2426 g_object_unref (info->banner);
2427 g_slice_free (SaveMimePartInfo, info);
2432 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2434 if (info->pairs != NULL) {
2435 save_mime_part_to_file (info);
2438 result = info->result;
2440 /* This is a GDK lock because we are an idle callback and
2441 * hildon_banner_show_information is or does Gtk+ code */
2443 gdk_threads_enter (); /* CHECKED */
2444 save_mime_part_info_free (info, TRUE);
2446 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2448 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2450 gdk_threads_leave (); /* CHECKED */
2457 save_mime_part_to_file (SaveMimePartInfo *info)
2459 GnomeVFSResult result;
2460 GnomeVFSHandle *handle;
2462 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2464 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2465 if (result == GNOME_VFS_OK) {
2466 stream = tny_vfs_stream_new (handle);
2467 tny_mime_part_decode_to_stream (pair->part, stream);
2468 g_object_unref (G_OBJECT (stream));
2469 g_object_unref (pair->part);
2470 g_slice_free (SaveMimePartPair, pair);
2471 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2472 info->result = TRUE;
2474 save_mime_part_info_free (info, FALSE);
2475 info->result = FALSE;
2478 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2483 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2485 gboolean is_ok = TRUE;
2486 gint replaced_files = 0;
2487 const GList *files = info->pairs;
2490 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2491 SaveMimePartPair *pair = iter->data;
2492 if (modest_utils_file_exists (pair->filename)) {
2496 if (replaced_files) {
2497 GtkWidget *confirm_overwrite_dialog;
2498 const gchar *message = (replaced_files == 1) ?
2499 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2500 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2501 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2504 gtk_widget_destroy (confirm_overwrite_dialog);
2508 save_mime_part_info_free (info, TRUE);
2510 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2511 _CS("sfil_ib_saving"));
2512 info->banner = g_object_ref (banner);
2513 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2514 g_object_unref (banner);
2521 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2523 gboolean clean_list = FALSE;
2524 ModestMsgViewWindowPrivate *priv;
2525 GList *files_to_save = NULL;
2526 GtkWidget *save_dialog = NULL;
2527 gchar *folder = NULL;
2528 gboolean canceled = FALSE;
2529 const gchar *filename = NULL;
2530 gchar *save_multiple_str = NULL;
2532 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2535 if (mime_parts == NULL) {
2536 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2537 if (mime_parts == NULL)
2542 /* prepare dialog */
2543 if (mime_parts->next == NULL) {
2544 /* only one attachment selected */
2545 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2546 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2547 filename = tny_mime_part_get_filename (mime_part);
2549 g_warning ("Tried to save a non-file attachment");
2553 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2554 g_list_length (mime_parts));
2557 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2558 GTK_FILE_CHOOSER_ACTION_SAVE);
2561 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2562 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2566 if (filename != NULL)
2567 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2570 /* if multiple, set multiple string */
2571 if (save_multiple_str) {
2572 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2576 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2577 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2579 if (!modest_utils_folder_writable (chooser_uri)) {
2580 hildon_banner_show_information
2581 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2585 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2586 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2588 if (tny_mime_part_is_attachment (mime_part)) {
2589 SaveMimePartPair *pair;
2591 if ((mime_parts->next != NULL) &&
2592 (tny_mime_part_get_filename (mime_part) == NULL))
2595 pair = g_slice_new0 (SaveMimePartPair);
2596 if (mime_parts->next == NULL) {
2597 pair->filename = g_strdup (chooser_uri);
2600 g_build_filename (chooser_uri,
2601 tny_mime_part_get_filename (mime_part), NULL);
2603 pair->part = g_object_ref (mime_part);
2604 files_to_save = g_list_prepend (files_to_save, pair);
2608 g_free (chooser_uri);
2611 gtk_widget_destroy (save_dialog);
2614 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2615 g_list_free (mime_parts);
2618 if (files_to_save != NULL) {
2619 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2620 info->pairs = files_to_save;
2621 info->result = TRUE;
2622 save_mime_parts_to_file_with_checks (info);
2627 show_remove_attachment_information (gpointer userdata)
2629 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2630 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2632 /* We're outside the main lock */
2633 gdk_threads_enter ();
2635 if (priv->remove_attachment_banner != NULL) {
2636 gtk_widget_destroy (priv->remove_attachment_banner);
2637 g_object_unref (priv->remove_attachment_banner);
2640 priv->remove_attachment_banner = g_object_ref (
2641 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2643 gdk_threads_leave ();
2649 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2651 ModestMsgViewWindowPrivate *priv;
2652 GList *mime_parts = NULL, *node;
2653 gchar *confirmation_message;
2657 /* TnyFolder *folder; */
2659 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2660 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2663 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2665 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2667 /* Remove already purged messages from mime parts list */
2669 while (node != NULL) {
2670 TnyMimePart *part = TNY_MIME_PART (node->data);
2671 if (tny_mime_part_is_purged (part)) {
2672 GList *deleted_node = node;
2673 node = g_list_next (node);
2674 g_object_unref (part);
2675 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2677 node = g_list_next (node);
2681 if (mime_parts == NULL)
2684 n_attachments = g_list_length (mime_parts);
2685 if (n_attachments == 1) {
2686 const gchar *filename;
2688 if (TNY_IS_MSG (mime_parts->data)) {
2690 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2691 filename = tny_header_get_subject (header);
2692 g_object_unref (header);
2693 if (filename == NULL)
2694 filename = _("mail_va_no_subject");
2696 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2698 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2700 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2701 "mcen_nc_purge_files_text",
2702 n_attachments), n_attachments);
2704 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2705 confirmation_message);
2706 g_free (confirmation_message);
2708 if (response != GTK_RESPONSE_OK)
2711 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2712 /* folder = tny_msg_get_folder (msg); */
2713 /* tny_msg_uncache_attachments (msg); */
2714 /* tny_folder_refresh (folder, NULL); */
2715 /* g_object_unref (folder); */
2717 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2718 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2719 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2722 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2723 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2724 tny_msg_rewrite_cache (msg);
2725 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2727 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2728 g_list_free (mime_parts);
2730 if (priv->purge_timeout > 0) {
2731 g_source_remove (priv->purge_timeout);
2732 priv->purge_timeout = 0;
2735 if (priv->remove_attachment_banner) {
2736 gtk_widget_destroy (priv->remove_attachment_banner);
2737 g_object_unref (priv->remove_attachment_banner);
2738 priv->remove_attachment_banner = NULL;
2746 update_window_title (ModestMsgViewWindow *window)
2748 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2750 TnyHeader *header = NULL;
2751 const gchar *subject = NULL;
2753 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2756 header = tny_msg_get_header (msg);
2757 subject = tny_header_get_subject (header);
2758 g_object_unref (msg);
2761 if ((subject == NULL)||(subject[0] == '\0'))
2762 subject = _("mail_va_no_subject");
2764 gtk_window_set_title (GTK_WINDOW (window), subject);
2768 static void on_move_focus (GtkWidget *widget,
2769 GtkDirectionType direction,
2772 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");