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-main-window-ui.h>
43 #include "modest-msg-view-window-ui-dimming.h"
44 #include <modest-widget-memory.h>
45 #include <modest-runtime.h>
46 #include <modest-window-priv.h>
47 #include <modest-tny-folder.h>
48 #include <modest-text-utils.h>
49 #include <modest-account-mgr-helpers.h>
50 #include "modest-progress-bar.h"
51 #include "modest-defs.h"
52 #include "modest-hildon-includes.h"
53 #include "modest-ui-dimming-manager.h"
54 #include <gdk/gdkkeysyms.h>
55 #include <modest-tny-account.h>
56 #include <modest-mime-part-view.h>
57 #include <modest-isearch-view.h>
60 #include <glib/gstdio.h>
62 #define DEFAULT_FOLDER "MyDocs/.documents"
64 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
65 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
66 static void modest_header_view_observer_init(
67 ModestHeaderViewObserverIface *iface_class);
68 static void modest_msg_view_window_finalize (GObject *obj);
69 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
71 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
72 ModestMsgViewWindow *obj);
73 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
74 ModestMsgViewWindow *obj);
76 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
77 static void modest_msg_view_window_set_zoom (ModestWindow *window,
79 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
80 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
81 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
82 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
85 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
86 GdkEventWindowState *event,
88 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
90 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
91 gboolean show_toolbar);
93 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
95 ModestMsgViewWindow *window);
96 void modest_msg_view_window_on_row_changed(
97 GtkTreeModel *header_model,
100 ModestMsgViewWindow *window);
102 void modest_msg_view_window_on_row_deleted(
103 GtkTreeModel *header_model,
105 ModestMsgViewWindow *window);
107 void modest_msg_view_window_on_row_inserted(
108 GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 void modest_msg_view_window_on_row_reordered(
114 GtkTreeModel *header_model,
118 ModestMsgViewWindow *window);
120 void modest_msg_view_window_update_model_replaced(
121 ModestHeaderViewObserver *window,
123 const gchar *tny_folder_id);
125 static void cancel_progressbar (GtkToolButton *toolbutton,
126 ModestMsgViewWindow *self);
128 static void on_queue_changed (ModestMailOperationQueue *queue,
129 ModestMailOperation *mail_op,
130 ModestMailOperationQueueNotification type,
131 ModestMsgViewWindow *self);
133 static void on_account_removed (TnyAccountStore *account_store,
137 static void on_move_focus (GtkWidget *widget,
138 GtkDirectionType direction,
141 static void view_msg_cb (ModestMailOperation *mail_op,
148 static void set_toolbar_mode (ModestMsgViewWindow *self,
149 ModestToolBarModes mode);
151 static void update_window_title (ModestMsgViewWindow *window);
153 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
154 static void init_window (ModestMsgViewWindow *obj);
156 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
159 /* list my signals */
165 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
166 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
167 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
170 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
171 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
172 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
173 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
174 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
175 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
176 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
179 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
180 struct _ModestMsgViewWindowPrivate {
183 GtkWidget *main_scroll;
184 GtkWidget *find_toolbar;
187 /* Progress observers */
188 GtkWidget *progress_bar;
189 GSList *progress_widgets;
192 GtkWidget *progress_toolitem;
193 GtkWidget *cancel_toolitem;
194 GtkWidget *prev_toolitem;
195 GtkWidget *next_toolitem;
196 ModestToolBarModes current_toolbar_mode;
198 /* Optimized view enabled */
199 gboolean optimized_view;
201 /* Whether this was created via the *_new_for_search_result() function. */
202 gboolean is_search_result;
204 /* Whether the message is in outbox */
207 /* A reference to the @model of the header view
208 * to allow selecting previous/next messages,
209 * if the message is currently selected in the header view.
211 const gchar *header_folder_id;
212 GtkTreeModel *header_model;
213 GtkTreeRowReference *row_reference;
214 GtkTreeRowReference *next_row_reference;
216 gulong clipboard_change_handler;
217 gulong queue_change_handler;
218 gulong account_removed_handler;
219 gulong row_changed_handler;
220 gulong row_deleted_handler;
221 gulong row_inserted_handler;
222 gulong rows_reordered_handler;
225 GtkWidget *remove_attachment_banner;
227 guint progress_bar_timeout;
234 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
235 MODEST_TYPE_MSG_VIEW_WINDOW, \
236 ModestMsgViewWindowPrivate))
238 static GtkWindowClass *parent_class = NULL;
240 /* uncomment the following if you have defined any signals */
241 static guint signals[LAST_SIGNAL] = {0};
244 modest_msg_view_window_get_type (void)
246 static GType my_type = 0;
248 static const GTypeInfo my_info = {
249 sizeof(ModestMsgViewWindowClass),
250 NULL, /* base init */
251 NULL, /* base finalize */
252 (GClassInitFunc) modest_msg_view_window_class_init,
253 NULL, /* class finalize */
254 NULL, /* class data */
255 sizeof(ModestMsgViewWindow),
257 (GInstanceInitFunc) modest_msg_view_window_init,
260 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
261 "ModestMsgViewWindow",
264 static const GInterfaceInfo modest_header_view_observer_info =
266 (GInterfaceInitFunc) modest_header_view_observer_init,
267 NULL, /* interface_finalize */
268 NULL /* interface_data */
271 g_type_add_interface_static (my_type,
272 MODEST_TYPE_HEADER_VIEW_OBSERVER,
273 &modest_header_view_observer_info);
279 save_state (ModestWindow *self)
281 modest_widget_memory_save (modest_runtime_get_conf (),
283 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
288 restore_settings (ModestMsgViewWindow *self)
291 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
294 conf = modest_runtime_get_conf ();
295 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
296 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
297 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
298 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
299 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
300 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
301 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
302 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
303 modest_widget_memory_restore (conf,
305 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
309 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
311 GObjectClass *gobject_class;
312 ModestWindowClass *modest_window_class;
313 gobject_class = (GObjectClass*) klass;
314 modest_window_class = (ModestWindowClass *) klass;
316 parent_class = g_type_class_peek_parent (klass);
317 gobject_class->finalize = modest_msg_view_window_finalize;
319 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
320 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
321 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
322 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
323 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
324 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
326 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
328 modest_window_class->save_state_func = save_state;
330 signals[MSG_CHANGED_SIGNAL] =
331 g_signal_new ("msg-changed",
332 G_TYPE_FROM_CLASS (gobject_class),
334 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
336 modest_marshal_VOID__POINTER_POINTER,
337 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
340 static void modest_header_view_observer_init(
341 ModestHeaderViewObserverIface *iface_class)
343 iface_class->update_func = modest_msg_view_window_update_model_replaced;
347 modest_msg_view_window_init (ModestMsgViewWindow *obj)
349 ModestMsgViewWindowPrivate *priv;
350 ModestWindowPrivate *parent_priv = NULL;
351 GtkActionGroup *action_group = NULL;
352 GError *error = NULL;
353 GdkPixbuf *window_icon;
355 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
356 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
357 parent_priv->ui_manager = gtk_ui_manager_new();
359 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
360 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
362 /* Add common actions */
363 gtk_action_group_add_actions (action_group,
364 modest_action_entries,
365 G_N_ELEMENTS (modest_action_entries),
367 gtk_action_group_add_toggle_actions (action_group,
368 modest_toggle_action_entries,
369 G_N_ELEMENTS (modest_toggle_action_entries),
371 gtk_action_group_add_toggle_actions (action_group,
372 msg_view_toggle_action_entries,
373 G_N_ELEMENTS (msg_view_toggle_action_entries),
375 gtk_action_group_add_radio_actions (action_group,
376 msg_view_zoom_action_entries,
377 G_N_ELEMENTS (msg_view_zoom_action_entries),
379 G_CALLBACK (modest_ui_actions_on_change_zoom),
382 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
383 g_object_unref (action_group);
385 /* Load the UI definition */
386 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
389 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
390 g_error_free (error);
395 /* Add accelerators */
396 gtk_window_add_accel_group (GTK_WINDOW (obj),
397 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
399 priv->is_search_result = FALSE;
400 priv->is_outbox = FALSE;
402 priv->msg_view = NULL;
403 priv->header_model = NULL;
404 priv->header_folder_id = NULL;
405 priv->clipboard_change_handler = 0;
406 priv->queue_change_handler = 0;
407 priv->account_removed_handler = 0;
408 priv->row_changed_handler = 0;
409 priv->row_deleted_handler = 0;
410 priv->row_inserted_handler = 0;
411 priv->rows_reordered_handler = 0;
412 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
414 priv->optimized_view = FALSE;
415 priv->progress_bar_timeout = 0;
416 priv->purge_timeout = 0;
417 priv->remove_attachment_banner = NULL;
418 priv->msg_uid = NULL;
420 priv->sighandlers = NULL;
423 init_window (MODEST_MSG_VIEW_WINDOW(obj));
425 /* Set window icon */
426 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
428 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
429 g_object_unref (window_icon);
432 hildon_program_add_window (hildon_program_get_instance(),
435 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
436 GTK_WINDOW(obj),"applications_email_viewer");
441 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
443 ModestMsgViewWindowPrivate *priv = NULL;
445 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
447 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
449 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
451 if (priv->progress_bar_timeout > 0) {
452 g_source_remove (priv->progress_bar_timeout);
453 priv->progress_bar_timeout = 0;
460 set_toolbar_mode (ModestMsgViewWindow *self,
461 ModestToolBarModes mode)
463 ModestWindowPrivate *parent_priv;
464 ModestMsgViewWindowPrivate *priv;
465 /* GtkWidget *widget = NULL; */
467 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
469 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
470 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
472 /* Sets current toolbar mode */
473 priv->current_toolbar_mode = mode;
475 /* Update toolbar dimming state */
476 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
479 case TOOLBAR_MODE_NORMAL:
480 if (priv->progress_toolitem) {
481 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
482 gtk_widget_hide (priv->progress_toolitem);
485 if (priv->progress_bar)
486 gtk_widget_hide (priv->progress_bar);
488 if (priv->cancel_toolitem)
489 gtk_widget_hide (priv->cancel_toolitem);
491 if (priv->prev_toolitem)
492 gtk_widget_show (priv->prev_toolitem);
494 if (priv->next_toolitem)
495 gtk_widget_show (priv->next_toolitem);
497 /* Hide toolbar if optimized view is enabled */
498 if (priv->optimized_view) {
499 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
500 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
504 case TOOLBAR_MODE_TRANSFER:
505 if (priv->prev_toolitem)
506 gtk_widget_hide (priv->prev_toolitem);
508 if (priv->next_toolitem)
509 gtk_widget_hide (priv->next_toolitem);
511 if (priv->progress_bar)
512 gtk_widget_show (priv->progress_bar);
514 if (priv->progress_toolitem) {
515 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
516 gtk_widget_show (priv->progress_toolitem);
519 if (priv->cancel_toolitem)
520 gtk_widget_show (priv->cancel_toolitem);
522 /* Show toolbar if it's hiden (optimized view ) */
523 if (priv->optimized_view) {
524 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
525 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
530 g_return_if_reached ();
537 init_window (ModestMsgViewWindow *obj)
539 GtkWidget *main_vbox;
540 ModestMsgViewWindowPrivate *priv;
542 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
544 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
545 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
546 main_vbox = gtk_vbox_new (FALSE, 6);
548 #ifdef MODEST_USE_MOZEMBED
549 priv->main_scroll = priv->msg_view;
550 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
552 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
553 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
555 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
556 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
557 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
559 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
560 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
562 priv->find_toolbar = hildon_find_toolbar_new (NULL);
563 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
564 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
566 gtk_widget_show_all (GTK_WIDGET(main_vbox));
570 modest_msg_view_window_disconnect_signals (ModestWindow *self)
572 ModestMsgViewWindowPrivate *priv;
573 ModestHeaderView *header_view = NULL;
574 ModestWindow *main_window = NULL;
576 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
578 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
579 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
580 priv->clipboard_change_handler))
581 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
582 priv->clipboard_change_handler);
584 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
585 priv->queue_change_handler))
586 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
587 priv->queue_change_handler);
589 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
590 priv->account_removed_handler))
591 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
592 priv->account_removed_handler);
594 if (priv->header_model) {
595 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
596 priv->row_changed_handler))
597 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
598 priv->row_changed_handler);
600 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
601 priv->row_deleted_handler))
602 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
603 priv->row_deleted_handler);
605 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
606 priv->row_inserted_handler))
607 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
608 priv->row_inserted_handler);
610 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
611 priv->rows_reordered_handler))
612 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
613 priv->rows_reordered_handler);
616 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
617 priv->sighandlers = NULL;
619 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
620 FALSE); /* don't create */
624 header_view = MODEST_HEADER_VIEW(
625 modest_main_window_get_child_widget(
626 MODEST_MAIN_WINDOW(main_window),
627 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
628 if (header_view == NULL)
631 modest_header_view_remove_observer(header_view,
632 MODEST_HEADER_VIEW_OBSERVER(self));
636 modest_msg_view_window_finalize (GObject *obj)
638 ModestMsgViewWindowPrivate *priv;
640 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
642 /* Sanity check: shouldn't be needed, the window mgr should
643 call this function before */
644 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
646 if (priv->header_model != NULL) {
647 g_object_unref (priv->header_model);
648 priv->header_model = NULL;
651 if (priv->progress_bar_timeout > 0) {
652 g_source_remove (priv->progress_bar_timeout);
653 priv->progress_bar_timeout = 0;
656 if (priv->remove_attachment_banner) {
657 gtk_widget_destroy (priv->remove_attachment_banner);
658 g_object_unref (priv->remove_attachment_banner);
659 priv->remove_attachment_banner = NULL;
662 if (priv->purge_timeout > 0) {
663 g_source_remove (priv->purge_timeout);
664 priv->purge_timeout = 0;
667 if (priv->row_reference) {
668 gtk_tree_row_reference_free (priv->row_reference);
669 priv->row_reference = NULL;
672 if (priv->next_row_reference) {
673 gtk_tree_row_reference_free (priv->next_row_reference);
674 priv->next_row_reference = NULL;
678 g_free (priv->msg_uid);
679 priv->msg_uid = NULL;
682 G_OBJECT_CLASS(parent_class)->finalize (obj);
686 select_next_valid_row (GtkTreeModel *model,
687 GtkTreeRowReference **row_reference,
690 GtkTreeIter tmp_iter;
692 GtkTreePath *next = NULL;
693 gboolean retval = FALSE;
695 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
697 path = gtk_tree_row_reference_get_path (*row_reference);
698 gtk_tree_model_get_iter (model, &tmp_iter, path);
699 gtk_tree_row_reference_free (*row_reference);
700 *row_reference = NULL;
702 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
703 next = gtk_tree_model_get_path (model, &tmp_iter);
704 *row_reference = gtk_tree_row_reference_new (model, next);
706 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
707 next = gtk_tree_model_get_path (model, &tmp_iter);
709 /* Ensure that we are not selecting the same */
710 if (gtk_tree_path_compare (path, next) != 0) {
711 *row_reference = gtk_tree_row_reference_new (model, next);
717 gtk_tree_path_free (path);
719 gtk_tree_path_free (next);
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 (MODEST_DIMMING_RULES_MENU, FALSE);
750 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
751 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, 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 gtk_widget_show_all (GTK_WIDGET (obj));
828 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
833 /* FIXME: parameter checks */
835 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
836 const gchar *modest_account_name,
837 const gchar *msg_uid,
839 GtkTreeRowReference *row_reference)
841 ModestMsgViewWindow *window = NULL;
842 ModestMsgViewWindowPrivate *priv = NULL;
843 TnyFolder *header_folder = NULL;
844 ModestHeaderView *header_view = NULL;
845 ModestWindow *main_window = NULL;
846 ModestWindowMgr *mgr = NULL;
848 mgr = modest_runtime_get_window_mgr ();
849 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
850 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
852 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
854 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
856 /* Remember the message list's TreeModel so we can detect changes
857 * and change the list selection when necessary: */
859 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
861 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
862 MODEST_MAIN_WINDOW(main_window),
863 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
866 if (header_view != NULL){
867 header_folder = modest_header_view_get_folder(header_view);
868 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) == TNY_FOLDER_TYPE_OUTBOX);
869 g_assert(header_folder != NULL);
870 priv->header_folder_id = tny_folder_get_id(header_folder);
871 g_assert(priv->header_folder_id != NULL);
872 g_object_unref(header_folder);
875 priv->header_model = g_object_ref(model);
877 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
878 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
879 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
881 priv->row_reference = NULL;
882 priv->next_row_reference = NULL;
885 priv->row_changed_handler = g_signal_connect(
886 GTK_TREE_MODEL(model), "row-changed",
887 G_CALLBACK(modest_msg_view_window_on_row_changed),
889 priv->row_deleted_handler = g_signal_connect(
890 GTK_TREE_MODEL(model), "row-deleted",
891 G_CALLBACK(modest_msg_view_window_on_row_deleted),
893 priv->row_inserted_handler = g_signal_connect (
894 GTK_TREE_MODEL(model), "row-inserted",
895 G_CALLBACK(modest_msg_view_window_on_row_inserted),
897 priv->rows_reordered_handler = g_signal_connect(
898 GTK_TREE_MODEL(model), "rows-reordered",
899 G_CALLBACK(modest_msg_view_window_on_row_reordered),
902 if (header_view != NULL){
903 modest_header_view_add_observer(header_view,
904 MODEST_HEADER_VIEW_OBSERVER(window));
907 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
908 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
909 gtk_widget_show_all (GTK_WIDGET (window));
910 modest_msg_view_window_update_priority (window);
912 /* Check dimming rules */
913 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
914 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
915 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
917 return MODEST_WINDOW(window);
921 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
922 const gchar *modest_account_name,
923 const gchar *msg_uid)
925 ModestMsgViewWindow *window = NULL;
926 ModestMsgViewWindowPrivate *priv = NULL;
927 ModestWindowMgr *mgr = NULL;
929 mgr = modest_runtime_get_window_mgr ();
930 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
931 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
932 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
934 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
936 /* Remember that this is a search result,
937 * so we can disable some UI appropriately: */
938 priv->is_search_result = TRUE;
940 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
942 update_window_title (window);
943 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 /* Check dimming rules */
969 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
970 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
971 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
973 return MODEST_WINDOW(obj);
976 void modest_msg_view_window_on_row_changed(
977 GtkTreeModel *header_model,
980 ModestMsgViewWindow *window){
981 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
984 void modest_msg_view_window_on_row_deleted(
985 GtkTreeModel *header_model,
987 ModestMsgViewWindow *window){
988 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
991 /* On insertions we check if the folder still has the message we are
992 * showing or do not. If do not, we do nothing. Which means we are still
993 * not attached to any header folder and thus next/prev buttons are
994 * still dimmed. Once the message that is shown by msg-view is found, the
995 * new model of header-view will be attached and the references will be set.
996 * On each further insertions dimming rules will be checked. However
997 * this requires extra CPU time at least works.
998 * (An message might be deleted from TnyFolder and thus will not be
999 * inserted into the model again for example if it is removed by the
1000 * imap server and the header view is refreshed.)
1002 void modest_msg_view_window_on_row_inserted(
1003 GtkTreeModel *new_model,
1004 GtkTreePath *tree_path,
1005 GtkTreeIter *tree_iter,
1006 ModestMsgViewWindow *window){
1007 ModestMsgViewWindowPrivate *priv = NULL;
1008 TnyHeader *header = NULL;
1011 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1013 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1015 /* If we already has a model attached then the message shown by
1016 * msg-view is in it, and thus we do not need any actions but
1017 * to check the dimming rules.*/
1018 if(priv->header_model != NULL){
1019 if (priv->row_reference) {
1020 gtk_tree_row_reference_free(priv->next_row_reference);
1021 priv->next_row_reference = gtk_tree_row_reference_copy(
1022 priv->row_reference);
1023 select_next_valid_row (priv->header_model,
1024 &(priv->next_row_reference), FALSE);
1026 modest_ui_actions_check_toolbar_dimming_rules (
1027 MODEST_WINDOW (window));
1031 /* Check if the newly inserted message is the same we are actually
1032 * showing. IF not, we should remain detached from the header model
1033 * and thus prev and next toolbarbuttons should remain dimmed. */
1034 gtk_tree_model_get (new_model, tree_iter,
1035 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1036 uid = modest_tny_folder_get_header_unique_id(header);
1037 if(!g_str_equal(priv->msg_uid, uid)){
1039 g_object_unref(G_OBJECT(header));
1043 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1044 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1045 g_object_unref(G_OBJECT(header));
1049 /* Setup row_reference for the actual msg. */
1050 priv->row_reference = gtk_tree_row_reference_new(
1051 new_model, tree_path);
1052 if(priv->row_reference == NULL){
1053 g_warning("No reference for msg header item.");
1057 /* Attach new_model and connect some callback to it to become able
1058 * to detect changes in header-view. */
1059 priv->header_model = g_object_ref(new_model);
1060 g_signal_connect (new_model, "row-changed",
1061 G_CALLBACK (modest_msg_view_window_on_row_changed),
1063 g_signal_connect (new_model, "row-deleted",
1064 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1066 g_signal_connect (new_model, "rows-reordered",
1067 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1070 /* Now set up next_row_reference. */
1071 priv->next_row_reference = gtk_tree_row_reference_copy(
1072 priv->row_reference);
1073 select_next_valid_row (priv->header_model,
1074 &(priv->next_row_reference), FALSE);
1076 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1079 void modest_msg_view_window_on_row_reordered(
1080 GtkTreeModel *header_model,
1084 ModestMsgViewWindow *window){
1085 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1088 /* The modest_msg_view_window_update_model_replaced implements update
1089 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1090 * actually belongs to the header-view is the same as the TnyFolder of
1091 * the message of msg-view or not. If they are different, there is
1092 * nothing to do. If they are the same, then the model has replaced and
1093 * the reference in msg-view shall be replaced from the old model to
1094 * the new model. In this case the view will be detached from it's
1095 * header folder. From this point the next/prev buttons are dimmed.
1097 void modest_msg_view_window_update_model_replaced(
1098 ModestHeaderViewObserver *observer,
1099 GtkTreeModel *model,
1100 const gchar *tny_folder_id){
1101 ModestMsgViewWindowPrivate *priv = NULL;
1102 ModestMsgViewWindow *window = NULL;
1104 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1105 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1107 window = MODEST_MSG_VIEW_WINDOW(observer);
1108 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1110 /* If there is an other folder in the header-view then we do
1111 * not care about it's model (msg list). Else if the
1112 * header-view shows the folder the msg shown by us is in, we
1113 * shall replace our model reference and make some check. */
1114 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1117 /* Model is changed(replaced), so we should forget the old
1118 * one. Because there might be other references and there
1119 * might be some change on the model even if we unreferenced
1120 * it, we need to disconnect our signals here. */
1121 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1122 priv->row_changed_handler))
1123 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1124 priv->row_changed_handler);
1125 priv->row_changed_handler = 0;
1126 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1127 priv->row_deleted_handler))
1128 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1129 priv->row_deleted_handler);
1130 priv->row_deleted_handler = 0;
1131 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1132 priv->row_inserted_handler))
1133 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1134 priv->row_inserted_handler);
1135 priv->row_inserted_handler = 0;
1136 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1137 priv->rows_reordered_handler))
1138 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1139 priv->rows_reordered_handler);
1140 priv->rows_reordered_handler = 0;
1141 g_object_unref(priv->header_model);
1142 priv->header_model = NULL;
1143 if (priv->row_reference)
1144 gtk_tree_row_reference_free (priv->row_reference);
1145 priv->row_reference = NULL;
1146 if (priv->next_row_reference)
1147 gtk_tree_row_reference_free (priv->next_row_reference);
1148 priv->next_row_reference = NULL;
1150 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1152 g_assert(model != NULL);
1154 /* Also we must connect to the new model for row insertions.
1155 * Only for insertions now. We will need other ones only after
1156 * the msg is show by msg-view is added to the new model. */
1157 priv->row_inserted_handler = g_signal_connect (
1158 model, "row-inserted",
1159 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1164 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1166 ModestMsgViewWindowPrivate *priv= NULL;
1168 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1169 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1171 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1175 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1177 ModestMsgViewWindowPrivate *priv= NULL;
1179 TnyHeader *header = NULL;
1180 GtkTreePath *path = NULL;
1183 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1184 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1186 /* If the message was not obtained from a treemodel,
1187 * for instance if it was opened directly by the search UI:
1189 if (priv->header_model == NULL ||
1190 priv->row_reference == NULL ||
1191 !gtk_tree_row_reference_valid (priv->row_reference)) {
1192 msg = modest_msg_view_window_get_message (self);
1194 header = tny_msg_get_header (msg);
1195 g_object_unref (msg);
1200 /* Get iter of the currently selected message in the header view: */
1201 path = gtk_tree_row_reference_get_path (priv->row_reference);
1202 g_return_val_if_fail (path != NULL, NULL);
1203 gtk_tree_model_get_iter (priv->header_model,
1207 /* Get current message header */
1208 gtk_tree_model_get (priv->header_model, &iter,
1209 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1212 gtk_tree_path_free (path);
1217 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1219 ModestMsgViewWindowPrivate *priv;
1221 g_return_val_if_fail (self, NULL);
1223 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1225 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1229 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1231 ModestMsgViewWindowPrivate *priv;
1233 g_return_val_if_fail (self, NULL);
1235 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1237 return (const gchar*) priv->msg_uid;
1241 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1244 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1245 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1246 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1250 is_active = gtk_toggle_action_get_active (toggle);
1253 gtk_widget_show (priv->find_toolbar);
1254 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1256 gtk_widget_hide (priv->find_toolbar);
1259 /* update the toggle buttons status */
1260 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1261 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1262 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1263 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1268 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1269 ModestMsgViewWindow *obj)
1271 GtkToggleAction *toggle;
1272 ModestWindowPrivate *parent_priv;
1273 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1275 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1276 gtk_toggle_action_set_active (toggle, FALSE);
1280 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1281 ModestMsgViewWindow *obj)
1283 gchar *current_search;
1284 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1286 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1287 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1291 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1293 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1294 g_free (current_search);
1295 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1299 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1301 g_free (priv->last_search);
1302 priv->last_search = g_strdup (current_search);
1303 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1306 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1307 g_free (priv->last_search);
1308 priv->last_search = NULL;
1310 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1313 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1314 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1315 g_free (priv->last_search);
1316 priv->last_search = NULL;
1318 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1322 g_free (current_search);
1327 modest_msg_view_window_set_zoom (ModestWindow *window,
1330 ModestMsgViewWindowPrivate *priv;
1331 ModestWindowPrivate *parent_priv;
1332 GtkAction *action = NULL;
1333 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1335 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1337 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1338 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1339 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1341 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1342 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1344 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1348 modest_msg_view_window_get_zoom (ModestWindow *window)
1350 ModestMsgViewWindowPrivate *priv;
1352 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1354 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1355 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1359 modest_msg_view_window_zoom_plus (ModestWindow *window)
1361 ModestWindowPrivate *parent_priv;
1362 GtkRadioAction *zoom_radio_action;
1363 GSList *group, *node;
1365 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1366 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1367 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1369 group = gtk_radio_action_get_group (zoom_radio_action);
1371 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1372 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1376 for (node = group; node != NULL; node = g_slist_next (node)) {
1377 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1378 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1386 modest_msg_view_window_zoom_minus (ModestWindow *window)
1388 ModestWindowPrivate *parent_priv;
1389 GtkRadioAction *zoom_radio_action;
1390 GSList *group, *node;
1392 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1393 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1394 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1396 group = gtk_radio_action_get_group (zoom_radio_action);
1398 for (node = group; node != NULL; node = g_slist_next (node)) {
1399 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1400 if (node->next != NULL) {
1401 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1404 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1414 modest_msg_view_window_key_event (GtkWidget *window,
1420 focus = gtk_window_get_focus (GTK_WINDOW (window));
1422 /* for the find toolbar case */
1423 if (focus && GTK_IS_ENTRY (focus)) {
1424 if (event->keyval == GDK_BackSpace) {
1426 copy = gdk_event_copy ((GdkEvent *) event);
1427 gtk_widget_event (focus, copy);
1428 gdk_event_free (copy);
1433 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1434 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1435 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1436 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1437 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1438 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1439 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1440 gboolean return_value;
1442 if (event->type == GDK_KEY_RELEASE) {
1443 GtkScrollType scroll_type;
1445 switch (event->keyval) {
1448 scroll_type = GTK_SCROLL_STEP_UP; break;
1451 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1453 case GDK_KP_Page_Up:
1454 scroll_type = GTK_SCROLL_PAGE_UP; break;
1456 case GDK_KP_Page_Down:
1457 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1460 scroll_type = GTK_SCROLL_START; break;
1463 scroll_type = GTK_SCROLL_END; break;
1464 default: scroll_type = GTK_SCROLL_NONE;
1467 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1468 scroll_type, FALSE, &return_value);
1479 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1482 ModestMsgViewWindowPrivate *priv;
1483 GtkTreeIter tmp_iter;
1484 gboolean is_last_selected;
1486 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1487 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1489 /*if no model (so no rows at all), then virtually we are the last*/
1490 if (!priv->header_model || !priv->row_reference)
1493 path = gtk_tree_row_reference_get_path (priv->row_reference);
1497 is_last_selected = TRUE;
1498 while (is_last_selected) {
1500 gtk_tree_path_next (path);
1501 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1503 gtk_tree_model_get (priv->header_model, &tmp_iter,
1504 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1507 if (msg_is_visible (header, priv->is_outbox))
1508 is_last_selected = FALSE;
1509 g_object_unref(G_OBJECT(header));
1512 gtk_tree_path_free (path);
1513 return is_last_selected;
1517 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1519 ModestMsgViewWindowPrivate *priv;
1521 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1522 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1524 return priv->header_model != NULL;
1528 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1530 ModestMsgViewWindowPrivate *priv;
1532 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1533 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1535 return priv->is_search_result;
1539 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1541 return (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) &&
1542 ( (!check_outbox) || (modest_tny_all_send_queues_get_msg_status (header) != MODEST_TNY_SEND_QUEUE_FAILED)) ;
1547 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1550 ModestMsgViewWindowPrivate *priv;
1551 gboolean is_first_selected;
1552 GtkTreeIter tmp_iter;
1553 /* gchar * path_string;*/
1555 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1556 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1558 /*if no model (so no rows at all), then virtually we are the first*/
1559 if (!priv->header_model || !priv->row_reference)
1562 path = gtk_tree_row_reference_get_path (priv->row_reference);
1566 /* path_string = gtk_tree_path_to_string (path);
1567 is_first_selected = strcmp (path_string, "0");
1569 g_free (path_string);
1570 gtk_tree_path_free (path);
1572 return is_first_selected;*/
1574 is_first_selected = TRUE;
1575 while (is_first_selected) {
1577 if(!gtk_tree_path_prev (path))
1579 /* Here the 'if' is needless for logic, but let make sure
1580 * iter is valid for gtk_tree_model_get. */
1581 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1583 gtk_tree_model_get (priv->header_model, &tmp_iter,
1584 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1587 if (msg_is_visible (header, priv->is_outbox))
1588 is_first_selected = FALSE;
1589 g_object_unref(G_OBJECT(header));
1592 gtk_tree_path_free (path);
1593 return is_first_selected;
1598 GtkTreeRowReference *row_reference;
1602 message_reader_performer (gboolean canceled,
1604 GtkWindow *parent_window,
1605 TnyAccount *account,
1608 ModestMailOperation *mail_op = NULL;
1609 MsgReaderInfo *info;
1611 info = (MsgReaderInfo *) user_data;
1612 if (canceled || err) {
1616 /* New mail operation */
1617 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1618 modest_ui_actions_get_msgs_full_error_handler,
1621 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1622 modest_mail_operation_get_msg (mail_op, info->header, view_msg_cb, info->row_reference);
1623 g_object_unref (mail_op);
1625 /* Update dimming rules */
1626 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (parent_window));
1627 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (parent_window));
1630 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1631 g_object_unref (info->header);
1632 g_slice_free (MsgReaderInfo, info);
1637 * Reads the message whose summary item is @header. It takes care of
1638 * several things, among others:
1640 * If the message was not previously downloaded then ask the user
1641 * before downloading. If there is no connection launch the connection
1642 * dialog. Update toolbar dimming rules.
1644 * Returns: TRUE if the mail operation was started, otherwise if the
1645 * user do not want to download the message, or if the user do not
1646 * want to connect, then the operation is not issued
1649 message_reader (ModestMsgViewWindow *window,
1650 ModestMsgViewWindowPrivate *priv,
1652 GtkTreeRowReference *row_reference)
1654 gboolean already_showing = FALSE;
1655 ModestWindow *msg_window = NULL;
1656 ModestWindowMgr *mgr;
1657 TnyAccount *account;
1659 MsgReaderInfo *info;
1661 g_return_val_if_fail (row_reference != NULL, FALSE);
1663 mgr = modest_runtime_get_window_mgr ();
1664 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1665 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1668 gtk_window_present (GTK_WINDOW (msg_window));
1669 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1673 /* Msg download completed */
1674 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1675 /* Ask the user if he wants to download the message if
1677 if (!tny_device_is_online (modest_runtime_get_device())) {
1678 GtkResponseType response;
1680 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1681 _("mcen_nc_get_msg"));
1682 if (response == GTK_RESPONSE_CANCEL)
1685 folder = tny_header_get_folder (header);
1686 info = g_slice_new (MsgReaderInfo);
1687 info->header = g_object_ref (header);
1688 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1690 /* Offer the connection dialog if necessary */
1691 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
1693 TNY_FOLDER_STORE (folder),
1694 message_reader_performer,
1696 g_object_unref (folder);
1701 folder = tny_header_get_folder (header);
1702 account = tny_folder_get_account (folder);
1703 info = g_slice_new (MsgReaderInfo);
1704 info->header = g_object_ref (header);
1705 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1707 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
1708 g_object_unref (account);
1709 g_object_unref (folder);
1715 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1717 ModestMsgViewWindowPrivate *priv;
1718 GtkTreePath *path= NULL;
1719 GtkTreeIter tmp_iter;
1721 gboolean retval = TRUE;
1722 GtkTreeRowReference *row_reference = NULL;
1724 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1725 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1727 if (!priv->row_reference)
1730 /* Update the next row reference if it's not valid. This could
1731 happen if for example the header which it was pointing to,
1732 was deleted. The best place to do it is in the row-deleted
1733 handler but the tinymail model do not work like the glib
1734 tree models and reports the deletion when the row is still
1736 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1737 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1738 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1739 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1742 if (priv->next_row_reference)
1743 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1747 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1749 gtk_tree_model_get_iter (priv->header_model,
1752 gtk_tree_path_free (path);
1754 gtk_tree_model_get (priv->header_model, &tmp_iter,
1755 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1758 /* Read the message & show it */
1759 if (!message_reader (window, priv, header, row_reference)) {
1762 gtk_tree_row_reference_free (row_reference);
1765 g_object_unref (header);
1771 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1773 ModestMsgViewWindowPrivate *priv = NULL;
1775 gboolean finished = FALSE;
1776 gboolean retval = FALSE;
1778 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1779 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1781 /* Return inmediatly if there is no header model */
1782 if (!priv->header_model || !priv->row_reference)
1785 path = gtk_tree_row_reference_get_path (priv->row_reference);
1786 while (!finished && gtk_tree_path_prev (path)) {
1790 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1791 gtk_tree_model_get (priv->header_model, &iter,
1792 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1796 if (msg_is_visible (header, priv->is_outbox)) {
1797 GtkTreeRowReference *row_reference;
1798 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1799 /* Read the message & show it */
1800 retval = message_reader (window, priv, header, row_reference);
1801 gtk_tree_row_reference_free (row_reference);
1805 g_object_unref (header);
1809 gtk_tree_path_free (path);
1814 view_msg_cb (ModestMailOperation *mail_op,
1821 ModestMsgViewWindow *self = NULL;
1822 ModestMsgViewWindowPrivate *priv = NULL;
1823 GtkTreeRowReference *row_reference = NULL;
1825 row_reference = (GtkTreeRowReference *) user_data;
1827 gtk_tree_row_reference_free (row_reference);
1831 /* If there was any error */
1832 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1833 gtk_tree_row_reference_free (row_reference);
1837 /* Get the window */
1838 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1839 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1840 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1842 /* Update the row reference */
1843 if (priv->row_reference != NULL) {
1844 gtk_tree_row_reference_free (priv->row_reference);
1845 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1846 if (priv->next_row_reference != NULL) {
1847 gtk_tree_row_reference_free (priv->next_row_reference);
1849 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1850 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1853 /* Mark header as read */
1854 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1855 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1857 /* Set new message */
1858 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
1859 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1860 modest_msg_view_window_update_priority (self);
1861 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1862 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1865 /* Set the new message uid of the window */
1866 if (priv->msg_uid) {
1867 g_free (priv->msg_uid);
1868 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1871 /* Notify the observers */
1872 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1873 0, priv->header_model, priv->row_reference);
1876 g_object_unref (self);
1877 gtk_tree_row_reference_free (row_reference);
1881 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1883 ModestMsgViewWindowPrivate *priv;
1885 TnyFolderType folder_type;
1887 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1889 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1891 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1895 folder = tny_msg_get_folder (msg);
1897 folder_type = modest_tny_folder_guess_folder_type (folder);
1898 g_object_unref (folder);
1900 g_object_unref (msg);
1908 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1910 ModestMsgViewWindowPrivate *priv;
1911 TnyHeader *header = NULL;
1912 TnyHeaderFlags flags = 0;
1914 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1916 if (priv->header_model && priv->row_reference) {
1918 GtkTreePath *path = NULL;
1920 path = gtk_tree_row_reference_get_path (priv->row_reference);
1921 g_return_if_fail (path != NULL);
1922 gtk_tree_model_get_iter (priv->header_model,
1924 gtk_tree_row_reference_get_path (priv->row_reference));
1926 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1928 gtk_tree_path_free (path);
1931 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1933 header = tny_msg_get_header (msg);
1934 g_object_unref (msg);
1939 flags = tny_header_get_flags (header);
1940 g_object_unref(G_OBJECT(header));
1943 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1948 toolbar_resize (ModestMsgViewWindow *self)
1950 ModestMsgViewWindowPrivate *priv = NULL;
1951 ModestWindowPrivate *parent_priv = NULL;
1953 gint static_button_size;
1954 ModestWindowMgr *mgr;
1956 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1957 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1958 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1960 mgr = modest_runtime_get_window_mgr ();
1961 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1963 if (parent_priv->toolbar) {
1964 /* left size buttons */
1965 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1966 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1967 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1968 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1969 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
1970 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1971 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1972 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1973 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1974 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1975 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1976 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1977 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1978 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1979 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1980 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1982 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1983 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1984 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1985 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1986 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
1987 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
1988 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
1989 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
1995 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1997 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1998 ModestWindowPrivate *parent_priv;
1999 ModestWindowMgr *mgr;
2000 gboolean is_fullscreen;
2001 GtkAction *fs_toggle_action;
2004 mgr = modest_runtime_get_window_mgr ();
2005 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2007 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2009 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2010 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2011 if (is_fullscreen != active) {
2012 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2014 toolbar_resize (MODEST_MSG_VIEW_WINDOW (widget));
2022 modest_msg_view_window_show_toolbar (ModestWindow *self,
2023 gboolean show_toolbar)
2025 ModestMsgViewWindowPrivate *priv = NULL;
2026 ModestWindowPrivate *parent_priv;
2027 GtkWidget *reply_button = NULL, *menu = NULL;
2028 GtkWidget *placeholder = NULL;
2030 const gchar *action_name;
2033 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2034 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2036 /* Set optimized view status */
2037 priv->optimized_view = !show_toolbar;
2039 if (!parent_priv->toolbar) {
2040 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2042 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2044 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
2045 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2046 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2047 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2048 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2050 /* Add ProgressBar (Transfer toolbar) */
2051 priv->progress_bar = modest_progress_bar_new ();
2052 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
2053 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
2054 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
2055 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
2056 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
2058 /* Connect cancel 'clicked' signal to abort progress mode */
2059 g_signal_connect(priv->cancel_toolitem, "clicked",
2060 G_CALLBACK(cancel_progressbar),
2063 /* Add it to the observers list */
2064 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
2067 hildon_window_add_toolbar (HILDON_WINDOW (self),
2068 GTK_TOOLBAR (parent_priv->toolbar));
2070 /* Set reply button tap and hold menu */
2071 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2072 "/ToolBar/ToolbarMessageReply");
2073 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2074 "/ToolbarReplyCSM");
2075 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2079 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2080 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2081 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2083 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2084 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2085 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2087 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2090 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2091 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2094 /* Update also the actions (to update the toggles in the
2095 menus), we have to do it manually because some other window
2096 of the same time could have changed it (remember that the
2097 toolbar fullscreen mode is shared by all the windows of the
2099 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2100 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2102 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2104 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2105 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2110 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2112 ModestMsgViewWindow *window)
2114 if (!GTK_WIDGET_VISIBLE (window))
2117 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2121 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2123 ModestMsgViewWindowPrivate *priv;
2125 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2126 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2128 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2132 cancel_progressbar (GtkToolButton *toolbutton,
2133 ModestMsgViewWindow *self)
2136 ModestMsgViewWindowPrivate *priv;
2138 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2140 /* Get operation observers and cancel its current operation */
2141 tmp = priv->progress_widgets;
2143 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2144 tmp=g_slist_next(tmp);
2148 observers_empty (ModestMsgViewWindow *self)
2151 ModestMsgViewWindowPrivate *priv;
2152 gboolean is_empty = TRUE;
2153 guint pending_ops = 0;
2155 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2156 tmp = priv->progress_widgets;
2158 /* Check all observers */
2159 while (tmp && is_empty) {
2160 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2161 is_empty = pending_ops == 0;
2163 tmp = g_slist_next(tmp);
2170 on_account_removed (TnyAccountStore *account_store,
2171 TnyAccount *account,
2174 /* Do nothing if it's a transport account, because we only
2175 show the messages of a store account */
2176 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2177 const gchar *parent_acc = NULL;
2178 const gchar *our_acc = NULL;
2180 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2181 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2183 /* Close this window if I'm showing a message of the removed account */
2184 if (strcmp (parent_acc, our_acc) == 0)
2185 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2190 on_mail_operation_started (ModestMailOperation *mail_op,
2193 ModestMsgViewWindow *self;
2194 ModestMailOperationTypeOperation op_type;
2196 ModestMsgViewWindowPrivate *priv;
2197 GObject *source = NULL;
2199 self = MODEST_MSG_VIEW_WINDOW (user_data);
2200 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2201 op_type = modest_mail_operation_get_type_operation (mail_op);
2202 tmp = priv->progress_widgets;
2203 source = modest_mail_operation_get_source(mail_op);
2204 if (G_OBJECT (self) == source) {
2205 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2206 set_toolbar_transfer_mode(self);
2208 modest_progress_object_add_operation (
2209 MODEST_PROGRESS_OBJECT (tmp->data),
2211 tmp = g_slist_next (tmp);
2215 g_object_unref (source);
2219 on_mail_operation_finished (ModestMailOperation *mail_op,
2222 ModestMsgViewWindow *self;
2223 ModestMailOperationTypeOperation op_type;
2225 ModestMsgViewWindowPrivate *priv;
2227 self = MODEST_MSG_VIEW_WINDOW (user_data);
2228 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2229 op_type = modest_mail_operation_get_type_operation (mail_op);
2230 tmp = priv->progress_widgets;
2232 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2234 modest_progress_object_remove_operation (
2235 MODEST_PROGRESS_OBJECT (tmp->data),
2237 tmp = g_slist_next (tmp);
2240 /* If no more operations are being observed, NORMAL mode is enabled again */
2241 if (observers_empty (self)) {
2242 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2248 on_queue_changed (ModestMailOperationQueue *queue,
2249 ModestMailOperation *mail_op,
2250 ModestMailOperationQueueNotification type,
2251 ModestMsgViewWindow *self)
2253 ModestMsgViewWindowPrivate *priv;
2255 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2257 /* If this operations was created by another window, do nothing */
2258 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2261 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2262 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2264 "operation-started",
2265 G_CALLBACK (on_mail_operation_started),
2267 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2269 "operation-finished",
2270 G_CALLBACK (on_mail_operation_finished),
2272 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2273 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2275 "operation-started");
2276 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2278 "operation-finished");
2283 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2285 ModestMsgViewWindowPrivate *priv;
2286 TnyList *selected_attachments = NULL;
2288 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2289 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2291 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2293 return selected_attachments;
2297 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2299 ModestMsgViewWindowPrivate *priv;
2300 const gchar *msg_uid;
2301 gchar *attachment_uid = NULL;
2302 gint attachment_index = 0;
2303 TnyList *attachments;
2305 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2306 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2307 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2309 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2310 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2311 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2312 g_object_unref (attachments);
2314 if (msg_uid && attachment_index >= 0) {
2315 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2318 if (mime_part == NULL) {
2319 gboolean error = FALSE;
2320 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2321 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2323 } else if (tny_list_get_length (selected_attachments) > 1) {
2324 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2328 iter = tny_list_create_iterator (selected_attachments);
2329 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2330 g_object_unref (iter);
2332 g_object_unref (selected_attachments);
2337 g_object_ref (mime_part);
2340 if (tny_mime_part_is_purged (mime_part)) {
2341 g_object_unref (mime_part);
2345 if (!TNY_IS_MSG (mime_part)) {
2346 gchar *filepath = NULL;
2347 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2348 const gchar *content_type;
2349 gboolean show_error_banner = FALSE;
2351 TnyFsStream *temp_stream = NULL;
2352 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2355 if (temp_stream != NULL) {
2356 content_type = tny_mime_part_get_content_type (mime_part);
2357 if (tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream), &err) >= 0) {
2358 /* make the file read-only */
2359 if (g_chmod(filepath, 0444) != 0)
2360 g_warning ("%s: failed to set file '%s' to read-only: %s",
2361 __FUNCTION__, filepath, strerror(errno));
2363 modest_platform_activate_file (filepath, content_type);
2365 /* error while saving attachment, maybe cerm_device_memory_full */
2366 show_error_banner = TRUE;
2368 g_warning ("%s: tny_mime_part_decode_to_stream failed (%s)", __FUNCTION__, err->message);
2372 g_object_unref (temp_stream);
2374 /* NOTE: files in the temporary area will be automatically
2375 * cleaned after some time if they are no longer in use */
2377 if (filepath != NULL) {
2378 /* the file may already exist but it isn't writable,
2379 * let's try to open it anyway */
2380 content_type = tny_mime_part_get_content_type (mime_part);
2381 modest_platform_activate_file (filepath, content_type);
2384 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2385 show_error_banner = TRUE;
2388 if (show_error_banner)
2389 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2391 /* message attachment */
2392 TnyHeader *header = NULL;
2393 ModestWindowMgr *mgr;
2394 ModestWindow *msg_win = NULL;
2397 header = tny_msg_get_header (TNY_MSG (mime_part));
2398 mgr = modest_runtime_get_window_mgr ();
2399 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2402 if (msg_win) /* there is already a window for this uid; top it */
2403 gtk_window_present (GTK_WINDOW(msg_win));
2405 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2406 * thus, we don't do anything */
2407 g_warning ("window for is already being created");
2409 /* it's not found, so create a new window for it */
2410 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2411 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2413 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2414 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2415 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2416 modest_window_get_zoom (MODEST_WINDOW (window)));
2417 modest_window_mgr_register_window (mgr, msg_win);
2418 gtk_widget_show_all (GTK_WIDGET (msg_win));
2421 g_object_unref (mime_part);
2437 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2438 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2439 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2440 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2443 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2447 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2448 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2449 g_free (pair->filename);
2450 g_object_unref (pair->part);
2451 g_slice_free (SaveMimePartPair, pair);
2453 g_list_free (info->pairs);
2456 gtk_widget_destroy (info->banner);
2457 g_slice_free (SaveMimePartInfo, info);
2462 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2464 if (info->pairs != NULL) {
2465 save_mime_part_to_file (info);
2468 result = info->result;
2470 /* This is a GDK lock because we are an idle callback and
2471 * hildon_banner_show_information is or does Gtk+ code */
2473 gdk_threads_enter (); /* CHECKED */
2474 save_mime_part_info_free (info, TRUE);
2476 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2478 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2480 gdk_threads_leave (); /* CHECKED */
2487 save_mime_part_to_file (SaveMimePartInfo *info)
2489 GnomeVFSResult result;
2490 GnomeVFSHandle *handle;
2492 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2493 gboolean decode_result = TRUE;
2495 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2496 if (result == GNOME_VFS_OK) {
2497 stream = tny_vfs_stream_new (handle);
2498 if (tny_mime_part_decode_to_stream (pair->part, stream, NULL) < 0) {
2499 decode_result = FALSE;
2501 g_object_unref (G_OBJECT (stream));
2502 g_object_unref (pair->part);
2503 g_slice_free (SaveMimePartPair, pair);
2504 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2505 info->result = decode_result;
2507 save_mime_part_info_free (info, FALSE);
2508 info->result = FALSE;
2511 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2516 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2518 gboolean is_ok = TRUE;
2519 gint replaced_files = 0;
2520 const GList *files = info->pairs;
2523 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2524 SaveMimePartPair *pair = iter->data;
2525 if (modest_utils_file_exists (pair->filename)) {
2529 if (replaced_files) {
2530 GtkWidget *confirm_overwrite_dialog;
2531 const gchar *message = (replaced_files == 1) ?
2532 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2533 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2534 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2537 gtk_widget_destroy (confirm_overwrite_dialog);
2541 save_mime_part_info_free (info, TRUE);
2543 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2544 _CS("sfil_ib_saving"));
2545 info->banner = banner;
2546 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2553 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, TnyList *mime_parts)
2555 ModestMsgViewWindowPrivate *priv;
2556 GList *files_to_save = NULL;
2557 GtkWidget *save_dialog = NULL;
2558 gchar *folder = NULL;
2559 gboolean canceled = FALSE;
2560 const gchar *filename = NULL;
2561 gchar *save_multiple_str = NULL;
2563 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2564 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2566 if (mime_parts == NULL) {
2567 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2568 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0)
2571 g_object_ref (mime_parts);
2574 /* prepare dialog */
2575 if (tny_list_get_length (mime_parts) == 1) {
2577 /* only one attachment selected */
2578 iter = tny_list_create_iterator (mime_parts);
2579 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2580 g_object_unref (iter);
2581 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2582 filename = tny_mime_part_get_filename (mime_part);
2584 g_warning ("Tried to save a non-file attachment");
2587 g_object_unref (mime_part);
2589 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2590 tny_list_get_length (mime_parts));
2593 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2594 GTK_FILE_CHOOSER_ACTION_SAVE);
2597 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2598 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2602 if (filename != NULL)
2603 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2606 /* if multiple, set multiple string */
2607 if (save_multiple_str) {
2608 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2612 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2613 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2615 if (!modest_utils_folder_writable (chooser_uri)) {
2616 hildon_banner_show_information
2617 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2621 iter = tny_list_create_iterator (mime_parts);
2622 while (!tny_iterator_is_done (iter)) {
2623 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2625 if ((tny_mime_part_is_attachment (mime_part)) &&
2626 (tny_mime_part_get_filename (mime_part) != NULL)) {
2627 SaveMimePartPair *pair;
2629 pair = g_slice_new0 (SaveMimePartPair);
2630 if (save_multiple_str) {
2632 g_build_filename (chooser_uri,
2633 tny_mime_part_get_filename (mime_part), NULL);
2635 pair->filename = g_strdup (chooser_uri);
2637 pair->part = mime_part;
2638 files_to_save = g_list_prepend (files_to_save, pair);
2640 tny_iterator_next (iter);
2642 g_object_unref (iter);
2644 g_free (chooser_uri);
2647 gtk_widget_destroy (save_dialog);
2649 g_object_unref (mime_parts);
2651 if (files_to_save != NULL) {
2652 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2653 info->pairs = files_to_save;
2654 info->result = TRUE;
2655 save_mime_parts_to_file_with_checks (info);
2660 show_remove_attachment_information (gpointer userdata)
2662 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2663 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2665 /* We're outside the main lock */
2666 gdk_threads_enter ();
2668 if (priv->remove_attachment_banner != NULL) {
2669 gtk_widget_destroy (priv->remove_attachment_banner);
2670 g_object_unref (priv->remove_attachment_banner);
2673 priv->remove_attachment_banner = g_object_ref (
2674 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2676 gdk_threads_leave ();
2682 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2684 ModestMsgViewWindowPrivate *priv;
2685 TnyList *mime_parts = NULL;
2686 gchar *confirmation_message;
2691 /* TnyFolder *folder; */
2693 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2694 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2697 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2699 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2701 /* Remove already purged messages from mime parts list */
2702 iter = tny_list_create_iterator (mime_parts);
2703 while (!tny_iterator_is_done (iter)) {
2704 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
2705 tny_iterator_next (iter);
2706 if (tny_mime_part_is_purged (part)) {
2707 tny_list_remove (mime_parts, (GObject *) part);
2709 g_object_unref (part);
2711 g_object_unref (iter);
2713 if (tny_list_get_length (mime_parts) == 0) {
2714 g_object_unref (mime_parts);
2718 n_attachments = tny_list_get_length (mime_parts);
2719 if (n_attachments == 1) {
2720 const gchar *filename;
2723 iter = tny_list_create_iterator (mime_parts);
2724 part = (TnyMimePart *) tny_iterator_get_current (iter);
2725 g_object_unref (iter);
2726 if (TNY_IS_MSG (part)) {
2728 header = tny_msg_get_header (TNY_MSG (part));
2729 filename = tny_header_get_subject (header);
2730 g_object_unref (header);
2731 if (filename == NULL)
2732 filename = _("mail_va_no_subject");
2734 filename = tny_mime_part_get_filename (TNY_MIME_PART (part));
2736 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2737 g_object_unref (part);
2739 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2740 "mcen_nc_purge_files_text",
2741 n_attachments), n_attachments);
2743 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2744 confirmation_message);
2745 g_free (confirmation_message);
2747 if (response != GTK_RESPONSE_OK) {
2748 g_object_unref (mime_parts);
2752 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2753 /* folder = tny_msg_get_folder (msg); */
2754 /* tny_msg_uncache_attachments (msg); */
2755 /* tny_folder_refresh (folder, NULL); */
2756 /* g_object_unref (folder); */
2758 iter = tny_list_create_iterator (mime_parts);
2759 while (!tny_iterator_is_done (iter)) {
2762 part = (TnyMimePart *) tny_iterator_get_current (iter);
2763 tny_mime_part_set_purged (TNY_MIME_PART (part));
2764 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2765 g_object_unref (part);
2766 tny_iterator_next (iter);
2768 g_object_unref (iter);
2770 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2771 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2772 tny_msg_rewrite_cache (msg);
2773 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2774 g_object_unref (msg);
2776 g_object_unref (mime_parts);
2778 if (priv->purge_timeout > 0) {
2779 g_source_remove (priv->purge_timeout);
2780 priv->purge_timeout = 0;
2783 if (priv->remove_attachment_banner) {
2784 gtk_widget_destroy (priv->remove_attachment_banner);
2785 g_object_unref (priv->remove_attachment_banner);
2786 priv->remove_attachment_banner = NULL;
2794 update_window_title (ModestMsgViewWindow *window)
2796 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2798 TnyHeader *header = NULL;
2799 const gchar *subject = NULL;
2801 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2804 header = tny_msg_get_header (msg);
2805 subject = tny_header_get_subject (header);
2806 g_object_unref (msg);
2809 if ((subject == NULL)||(subject[0] == '\0'))
2810 subject = _("mail_va_no_subject");
2812 gtk_window_set_title (GTK_WINDOW (window), subject);
2816 static void on_move_focus (GtkWidget *widget,
2817 GtkDirectionType direction,
2820 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");