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>
58 #include <modest-tny-mime-part.h>
61 #include <glib/gstdio.h>
62 #include <modest-debug.h>
64 #define DEFAULT_FOLDER "MyDocs/.documents"
66 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
67 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
68 static void modest_header_view_observer_init(
69 ModestHeaderViewObserverIface *iface_class);
70 static void modest_msg_view_window_finalize (GObject *obj);
71 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
73 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
74 ModestMsgViewWindow *obj);
75 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
76 ModestMsgViewWindow *obj);
78 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
79 static void modest_msg_view_window_set_zoom (ModestWindow *window,
81 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
82 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
83 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
84 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
87 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
88 GdkEventWindowState *event,
90 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
92 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
93 gboolean show_toolbar);
95 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
97 ModestMsgViewWindow *window);
98 void modest_msg_view_window_on_row_changed(
99 GtkTreeModel *header_model,
102 ModestMsgViewWindow *window);
104 void modest_msg_view_window_on_row_deleted(
105 GtkTreeModel *header_model,
107 ModestMsgViewWindow *window);
109 void modest_msg_view_window_on_row_inserted(
110 GtkTreeModel *header_model,
111 GtkTreePath *tree_path,
112 GtkTreeIter *tree_iter,
113 ModestMsgViewWindow *window);
115 void modest_msg_view_window_on_row_reordered(
116 GtkTreeModel *header_model,
120 ModestMsgViewWindow *window);
122 void modest_msg_view_window_update_model_replaced(
123 ModestHeaderViewObserver *window,
125 const gchar *tny_folder_id);
127 static void cancel_progressbar (GtkToolButton *toolbutton,
128 ModestMsgViewWindow *self);
130 static void on_queue_changed (ModestMailOperationQueue *queue,
131 ModestMailOperation *mail_op,
132 ModestMailOperationQueueNotification type,
133 ModestMsgViewWindow *self);
135 static void on_account_removed (TnyAccountStore *account_store,
139 static void on_move_focus (GtkWidget *widget,
140 GtkDirectionType direction,
143 static void view_msg_cb (ModestMailOperation *mail_op,
150 static void set_toolbar_mode (ModestMsgViewWindow *self,
151 ModestToolBarModes mode);
153 static void update_window_title (ModestMsgViewWindow *window);
155 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
156 static void init_window (ModestMsgViewWindow *obj);
158 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
161 /* list my signals */
167 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
168 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
169 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
172 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
173 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
174 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
175 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
176 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
177 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
178 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
181 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
182 struct _ModestMsgViewWindowPrivate {
185 GtkWidget *main_scroll;
186 GtkWidget *find_toolbar;
189 /* Progress observers */
190 GtkWidget *progress_bar;
191 GSList *progress_widgets;
194 GtkWidget *progress_toolitem;
195 GtkWidget *cancel_toolitem;
196 GtkWidget *prev_toolitem;
197 GtkWidget *next_toolitem;
198 ModestToolBarModes current_toolbar_mode;
200 /* Optimized view enabled */
201 gboolean optimized_view;
203 /* Whether this was created via the *_new_for_search_result() function. */
204 gboolean is_search_result;
206 /* Whether the message is in outbox */
209 /* A reference to the @model of the header view
210 * to allow selecting previous/next messages,
211 * if the message is currently selected in the header view.
213 const gchar *header_folder_id;
214 GtkTreeModel *header_model;
215 GtkTreeRowReference *row_reference;
216 GtkTreeRowReference *next_row_reference;
218 gulong clipboard_change_handler;
219 gulong queue_change_handler;
220 gulong account_removed_handler;
221 gulong row_changed_handler;
222 gulong row_deleted_handler;
223 gulong row_inserted_handler;
224 gulong rows_reordered_handler;
227 GtkWidget *remove_attachment_banner;
229 guint progress_bar_timeout;
236 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
237 MODEST_TYPE_MSG_VIEW_WINDOW, \
238 ModestMsgViewWindowPrivate))
240 static GtkWindowClass *parent_class = NULL;
242 /* uncomment the following if you have defined any signals */
243 static guint signals[LAST_SIGNAL] = {0};
246 modest_msg_view_window_get_type (void)
248 static GType my_type = 0;
250 static const GTypeInfo my_info = {
251 sizeof(ModestMsgViewWindowClass),
252 NULL, /* base init */
253 NULL, /* base finalize */
254 (GClassInitFunc) modest_msg_view_window_class_init,
255 NULL, /* class finalize */
256 NULL, /* class data */
257 sizeof(ModestMsgViewWindow),
259 (GInstanceInitFunc) modest_msg_view_window_init,
262 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
263 "ModestMsgViewWindow",
266 static const GInterfaceInfo modest_header_view_observer_info =
268 (GInterfaceInitFunc) modest_header_view_observer_init,
269 NULL, /* interface_finalize */
270 NULL /* interface_data */
273 g_type_add_interface_static (my_type,
274 MODEST_TYPE_HEADER_VIEW_OBSERVER,
275 &modest_header_view_observer_info);
281 save_state (ModestWindow *self)
283 modest_widget_memory_save (modest_runtime_get_conf (),
285 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
290 restore_settings (ModestMsgViewWindow *self)
293 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
296 conf = modest_runtime_get_conf ();
297 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
298 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
299 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
300 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
301 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
302 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
303 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
304 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
305 modest_widget_memory_restore (conf,
307 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
311 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
313 GObjectClass *gobject_class;
314 ModestWindowClass *modest_window_class;
315 gobject_class = (GObjectClass*) klass;
316 modest_window_class = (ModestWindowClass *) klass;
318 parent_class = g_type_class_peek_parent (klass);
319 gobject_class->finalize = modest_msg_view_window_finalize;
321 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
322 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
323 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
324 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
325 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
326 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
328 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
330 modest_window_class->save_state_func = save_state;
332 signals[MSG_CHANGED_SIGNAL] =
333 g_signal_new ("msg-changed",
334 G_TYPE_FROM_CLASS (gobject_class),
336 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
338 modest_marshal_VOID__POINTER_POINTER,
339 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
342 static void modest_header_view_observer_init(
343 ModestHeaderViewObserverIface *iface_class)
345 iface_class->update_func = modest_msg_view_window_update_model_replaced;
349 modest_msg_view_window_init (ModestMsgViewWindow *obj)
351 ModestMsgViewWindowPrivate *priv;
352 ModestWindowPrivate *parent_priv = NULL;
353 GtkActionGroup *action_group = NULL;
354 GError *error = NULL;
355 GdkPixbuf *window_icon;
357 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
358 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
359 parent_priv->ui_manager = gtk_ui_manager_new();
361 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
362 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
364 /* Add common actions */
365 gtk_action_group_add_actions (action_group,
366 modest_action_entries,
367 G_N_ELEMENTS (modest_action_entries),
369 gtk_action_group_add_toggle_actions (action_group,
370 modest_toggle_action_entries,
371 G_N_ELEMENTS (modest_toggle_action_entries),
373 gtk_action_group_add_toggle_actions (action_group,
374 msg_view_toggle_action_entries,
375 G_N_ELEMENTS (msg_view_toggle_action_entries),
377 gtk_action_group_add_radio_actions (action_group,
378 msg_view_zoom_action_entries,
379 G_N_ELEMENTS (msg_view_zoom_action_entries),
381 G_CALLBACK (modest_ui_actions_on_change_zoom),
384 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
385 g_object_unref (action_group);
387 /* Load the UI definition */
388 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
391 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
392 g_error_free (error);
397 /* Add accelerators */
398 gtk_window_add_accel_group (GTK_WINDOW (obj),
399 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
401 priv->is_search_result = FALSE;
402 priv->is_outbox = FALSE;
404 priv->msg_view = NULL;
405 priv->header_model = NULL;
406 priv->header_folder_id = NULL;
407 priv->clipboard_change_handler = 0;
408 priv->queue_change_handler = 0;
409 priv->account_removed_handler = 0;
410 priv->row_changed_handler = 0;
411 priv->row_deleted_handler = 0;
412 priv->row_inserted_handler = 0;
413 priv->rows_reordered_handler = 0;
414 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
416 priv->optimized_view = FALSE;
417 priv->progress_bar_timeout = 0;
418 priv->purge_timeout = 0;
419 priv->remove_attachment_banner = NULL;
420 priv->msg_uid = NULL;
422 priv->sighandlers = NULL;
425 init_window (MODEST_MSG_VIEW_WINDOW(obj));
427 /* Set window icon */
428 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
430 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
431 g_object_unref (window_icon);
434 hildon_program_add_window (hildon_program_get_instance(),
437 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
438 GTK_WINDOW(obj),"applications_email_viewer");
443 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
445 ModestMsgViewWindowPrivate *priv = NULL;
447 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
449 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
451 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
453 if (priv->progress_bar_timeout > 0) {
454 g_source_remove (priv->progress_bar_timeout);
455 priv->progress_bar_timeout = 0;
462 set_toolbar_mode (ModestMsgViewWindow *self,
463 ModestToolBarModes mode)
465 ModestWindowPrivate *parent_priv;
466 ModestMsgViewWindowPrivate *priv;
467 /* GtkWidget *widget = NULL; */
469 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
471 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
472 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
474 /* Sets current toolbar mode */
475 priv->current_toolbar_mode = mode;
477 /* Update toolbar dimming state */
478 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
481 case TOOLBAR_MODE_NORMAL:
482 if (priv->progress_toolitem) {
483 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
484 gtk_widget_hide (priv->progress_toolitem);
487 if (priv->progress_bar)
488 gtk_widget_hide (priv->progress_bar);
490 if (priv->cancel_toolitem)
491 gtk_widget_hide (priv->cancel_toolitem);
493 if (priv->prev_toolitem)
494 gtk_widget_show (priv->prev_toolitem);
496 if (priv->next_toolitem)
497 gtk_widget_show (priv->next_toolitem);
499 /* Hide toolbar if optimized view is enabled */
500 if (priv->optimized_view) {
501 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
502 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
506 case TOOLBAR_MODE_TRANSFER:
507 if (priv->prev_toolitem)
508 gtk_widget_hide (priv->prev_toolitem);
510 if (priv->next_toolitem)
511 gtk_widget_hide (priv->next_toolitem);
513 if (priv->progress_bar)
514 gtk_widget_show (priv->progress_bar);
516 if (priv->progress_toolitem) {
517 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
518 gtk_widget_show (priv->progress_toolitem);
521 if (priv->cancel_toolitem)
522 gtk_widget_show (priv->cancel_toolitem);
524 /* Show toolbar if it's hiden (optimized view ) */
525 if (priv->optimized_view) {
526 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
527 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
532 g_return_if_reached ();
539 init_window (ModestMsgViewWindow *obj)
541 GtkWidget *main_vbox;
542 ModestMsgViewWindowPrivate *priv;
544 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
546 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
547 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
548 main_vbox = gtk_vbox_new (FALSE, 6);
550 #ifdef MODEST_USE_MOZEMBED
551 priv->main_scroll = priv->msg_view;
552 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
554 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
555 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
557 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
558 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
559 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
561 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
562 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
564 priv->find_toolbar = hildon_find_toolbar_new (NULL);
565 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
566 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
568 gtk_widget_show_all (GTK_WIDGET(main_vbox));
572 modest_msg_view_window_disconnect_signals (ModestWindow *self)
574 ModestMsgViewWindowPrivate *priv;
575 ModestHeaderView *header_view = NULL;
576 ModestWindow *main_window = NULL;
578 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
580 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
581 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
582 priv->clipboard_change_handler))
583 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
584 priv->clipboard_change_handler);
586 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
587 priv->queue_change_handler))
588 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
589 priv->queue_change_handler);
591 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
592 priv->account_removed_handler))
593 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
594 priv->account_removed_handler);
596 if (priv->header_model) {
597 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
598 priv->row_changed_handler))
599 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
600 priv->row_changed_handler);
602 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
603 priv->row_deleted_handler))
604 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
605 priv->row_deleted_handler);
607 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
608 priv->row_inserted_handler))
609 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
610 priv->row_inserted_handler);
612 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
613 priv->rows_reordered_handler))
614 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
615 priv->rows_reordered_handler);
618 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
619 priv->sighandlers = NULL;
621 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
622 FALSE); /* don't create */
626 header_view = MODEST_HEADER_VIEW(
627 modest_main_window_get_child_widget(
628 MODEST_MAIN_WINDOW(main_window),
629 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
630 if (header_view == NULL)
633 modest_header_view_remove_observer(header_view,
634 MODEST_HEADER_VIEW_OBSERVER(self));
638 modest_msg_view_window_finalize (GObject *obj)
640 ModestMsgViewWindowPrivate *priv;
642 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
644 /* Sanity check: shouldn't be needed, the window mgr should
645 call this function before */
646 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
648 if (priv->header_model != NULL) {
649 g_object_unref (priv->header_model);
650 priv->header_model = NULL;
653 if (priv->progress_bar_timeout > 0) {
654 g_source_remove (priv->progress_bar_timeout);
655 priv->progress_bar_timeout = 0;
658 if (priv->remove_attachment_banner) {
659 gtk_widget_destroy (priv->remove_attachment_banner);
660 g_object_unref (priv->remove_attachment_banner);
661 priv->remove_attachment_banner = NULL;
664 if (priv->purge_timeout > 0) {
665 g_source_remove (priv->purge_timeout);
666 priv->purge_timeout = 0;
669 if (priv->row_reference) {
670 gtk_tree_row_reference_free (priv->row_reference);
671 priv->row_reference = NULL;
674 if (priv->next_row_reference) {
675 gtk_tree_row_reference_free (priv->next_row_reference);
676 priv->next_row_reference = NULL;
680 g_free (priv->msg_uid);
681 priv->msg_uid = NULL;
684 G_OBJECT_CLASS(parent_class)->finalize (obj);
688 select_next_valid_row (GtkTreeModel *model,
689 GtkTreeRowReference **row_reference,
692 GtkTreeIter tmp_iter;
694 GtkTreePath *next = NULL;
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);
721 gtk_tree_path_free (next);
726 /* TODO: This should be in _init(), with the parameters as properties. */
728 modest_msg_view_window_construct (ModestMsgViewWindow *self,
729 const gchar *modest_account_name,
730 const gchar *msg_uid)
733 ModestMsgViewWindowPrivate *priv = NULL;
734 ModestWindowPrivate *parent_priv = NULL;
735 ModestDimmingRulesGroup *menu_rules_group = NULL;
736 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
737 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
739 obj = G_OBJECT (self);
740 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
741 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
743 priv->msg_uid = g_strdup (msg_uid);
746 parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
747 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
748 gtk_widget_show (parent_priv->menubar);
749 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
751 menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
752 toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
753 clipboard_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_CLIPBOARD, FALSE);
755 /* Add common dimming rules */
756 modest_dimming_rules_group_add_rules (menu_rules_group,
757 modest_msg_view_menu_dimming_entries,
758 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
759 MODEST_WINDOW (self));
760 modest_dimming_rules_group_add_rules (toolbar_rules_group,
761 modest_msg_view_toolbar_dimming_entries,
762 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
763 MODEST_WINDOW (self));
764 modest_dimming_rules_group_add_rules (clipboard_rules_group,
765 modest_msg_view_clipboard_dimming_entries,
766 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
767 MODEST_WINDOW (self));
769 /* Insert dimming rules group for this window */
770 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
771 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
772 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
773 g_object_unref (menu_rules_group);
774 g_object_unref (toolbar_rules_group);
775 g_object_unref (clipboard_rules_group);
777 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
779 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
781 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
782 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
783 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
784 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
785 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
786 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
787 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
788 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
789 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
790 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
791 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
793 g_signal_connect (G_OBJECT (obj), "key-release-event",
794 G_CALLBACK (modest_msg_view_window_key_event),
797 g_signal_connect (G_OBJECT (obj), "key-press-event",
798 G_CALLBACK (modest_msg_view_window_key_event),
801 g_signal_connect (G_OBJECT (obj), "window-state-event",
802 G_CALLBACK (modest_msg_view_window_window_state_event),
805 g_signal_connect (G_OBJECT (obj), "move-focus",
806 G_CALLBACK (on_move_focus), obj);
808 /* Mail Operation Queue */
809 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
811 G_CALLBACK (on_queue_changed),
814 /* Account manager */
815 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
817 G_CALLBACK(on_account_removed),
820 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
822 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
823 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
824 priv->last_search = NULL;
826 /* Init the clipboard actions dim status */
827 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
829 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
834 /* FIXME: parameter checks */
836 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
837 const gchar *modest_account_name,
838 const gchar *msg_uid,
840 GtkTreeRowReference *row_reference)
842 ModestMsgViewWindow *window = NULL;
843 ModestMsgViewWindowPrivate *priv = NULL;
844 TnyFolder *header_folder = NULL;
845 ModestHeaderView *header_view = NULL;
846 ModestWindow *main_window = NULL;
847 ModestWindowMgr *mgr = NULL;
850 modest_tny_mime_part_to_string (TNY_MIME_PART (msg), 0);
853 mgr = modest_runtime_get_window_mgr ();
854 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
855 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
857 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
859 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
861 /* Remember the message list's TreeModel so we can detect changes
862 * and change the list selection when necessary: */
864 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
866 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
867 MODEST_MAIN_WINDOW(main_window),
868 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
871 if (header_view != NULL){
872 header_folder = modest_header_view_get_folder(header_view);
873 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) == TNY_FOLDER_TYPE_OUTBOX);
874 g_assert(header_folder != NULL);
875 priv->header_folder_id = tny_folder_get_id(header_folder);
876 g_assert(priv->header_folder_id != NULL);
877 g_object_unref(header_folder);
880 priv->header_model = g_object_ref(model);
882 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
883 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
884 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
886 priv->row_reference = NULL;
887 priv->next_row_reference = NULL;
890 priv->row_changed_handler = g_signal_connect(
891 GTK_TREE_MODEL(model), "row-changed",
892 G_CALLBACK(modest_msg_view_window_on_row_changed),
894 priv->row_deleted_handler = g_signal_connect(
895 GTK_TREE_MODEL(model), "row-deleted",
896 G_CALLBACK(modest_msg_view_window_on_row_deleted),
898 priv->row_inserted_handler = g_signal_connect (
899 GTK_TREE_MODEL(model), "row-inserted",
900 G_CALLBACK(modest_msg_view_window_on_row_inserted),
902 priv->rows_reordered_handler = g_signal_connect(
903 GTK_TREE_MODEL(model), "rows-reordered",
904 G_CALLBACK(modest_msg_view_window_on_row_reordered),
907 if (header_view != NULL){
908 modest_header_view_add_observer(header_view,
909 MODEST_HEADER_VIEW_OBSERVER(window));
912 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
913 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
914 gtk_widget_show_all (GTK_WIDGET (window));
915 modest_msg_view_window_update_priority (window);
917 /* Check dimming rules */
918 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
919 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (window));
920 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
922 return MODEST_WINDOW(window);
926 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
927 const gchar *modest_account_name,
928 const gchar *msg_uid)
930 ModestMsgViewWindow *window = NULL;
931 ModestMsgViewWindowPrivate *priv = NULL;
932 ModestWindowMgr *mgr = NULL;
934 mgr = modest_runtime_get_window_mgr ();
935 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
936 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
937 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
939 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
941 /* Remember that this is a search result,
942 * so we can disable some UI appropriately: */
943 priv->is_search_result = TRUE;
945 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
947 update_window_title (window);
948 modest_msg_view_window_update_priority (window);
950 gtk_widget_show_all (GTK_WIDGET (window));
953 return MODEST_WINDOW(window);
957 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
958 const gchar *modest_account_name,
959 const gchar *msg_uid)
962 ModestMsgViewWindowPrivate *priv;
963 ModestWindowMgr *mgr = NULL;
965 g_return_val_if_fail (msg, NULL);
966 mgr = modest_runtime_get_window_mgr ();
967 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
968 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
969 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
970 modest_account_name, msg_uid);
972 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
973 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
975 gtk_widget_show_all (GTK_WIDGET (obj));
977 /* Check dimming rules */
978 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
979 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (obj));
980 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), MODEST_DIMMING_RULES_CLIPBOARD);
982 return MODEST_WINDOW(obj);
985 void modest_msg_view_window_on_row_changed(
986 GtkTreeModel *header_model,
989 ModestMsgViewWindow *window){
990 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
993 void modest_msg_view_window_on_row_deleted(
994 GtkTreeModel *header_model,
996 ModestMsgViewWindow *window){
997 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1000 /* On insertions we check if the folder still has the message we are
1001 * showing or do not. If do not, we do nothing. Which means we are still
1002 * not attached to any header folder and thus next/prev buttons are
1003 * still dimmed. Once the message that is shown by msg-view is found, the
1004 * new model of header-view will be attached and the references will be set.
1005 * On each further insertions dimming rules will be checked. However
1006 * this requires extra CPU time at least works.
1007 * (An message might be deleted from TnyFolder and thus will not be
1008 * inserted into the model again for example if it is removed by the
1009 * imap server and the header view is refreshed.)
1011 void modest_msg_view_window_on_row_inserted(
1012 GtkTreeModel *new_model,
1013 GtkTreePath *tree_path,
1014 GtkTreeIter *tree_iter,
1015 ModestMsgViewWindow *window){
1016 ModestMsgViewWindowPrivate *priv = NULL;
1017 TnyHeader *header = NULL;
1020 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1022 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1024 /* If we already has a model attached then the message shown by
1025 * msg-view is in it, and thus we do not need any actions but
1026 * to check the dimming rules.*/
1027 if(priv->header_model != NULL){
1028 if (priv->row_reference) {
1029 gtk_tree_row_reference_free(priv->next_row_reference);
1030 priv->next_row_reference = gtk_tree_row_reference_copy(
1031 priv->row_reference);
1032 select_next_valid_row (priv->header_model,
1033 &(priv->next_row_reference), FALSE);
1035 modest_ui_actions_check_toolbar_dimming_rules (
1036 MODEST_WINDOW (window));
1040 /* Check if the newly inserted message is the same we are actually
1041 * showing. IF not, we should remain detached from the header model
1042 * and thus prev and next toolbarbuttons should remain dimmed. */
1043 gtk_tree_model_get (new_model, tree_iter,
1044 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1045 uid = modest_tny_folder_get_header_unique_id(header);
1046 if(!g_str_equal(priv->msg_uid, uid)){
1048 g_object_unref(G_OBJECT(header));
1052 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1053 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1054 g_object_unref(G_OBJECT(header));
1058 /* Setup row_reference for the actual msg. */
1059 priv->row_reference = gtk_tree_row_reference_new(
1060 new_model, tree_path);
1061 if(priv->row_reference == NULL){
1062 g_warning("No reference for msg header item.");
1066 /* Attach new_model and connect some callback to it to become able
1067 * to detect changes in header-view. */
1068 priv->header_model = g_object_ref(new_model);
1069 g_signal_connect (new_model, "row-changed",
1070 G_CALLBACK (modest_msg_view_window_on_row_changed),
1072 g_signal_connect (new_model, "row-deleted",
1073 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1075 g_signal_connect (new_model, "rows-reordered",
1076 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1079 /* Now set up next_row_reference. */
1080 priv->next_row_reference = gtk_tree_row_reference_copy(
1081 priv->row_reference);
1082 select_next_valid_row (priv->header_model,
1083 &(priv->next_row_reference), FALSE);
1085 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1088 void modest_msg_view_window_on_row_reordered(
1089 GtkTreeModel *header_model,
1093 ModestMsgViewWindow *window){
1094 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1097 /* The modest_msg_view_window_update_model_replaced implements update
1098 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1099 * actually belongs to the header-view is the same as the TnyFolder of
1100 * the message of msg-view or not. If they are different, there is
1101 * nothing to do. If they are the same, then the model has replaced and
1102 * the reference in msg-view shall be replaced from the old model to
1103 * the new model. In this case the view will be detached from it's
1104 * header folder. From this point the next/prev buttons are dimmed.
1106 void modest_msg_view_window_update_model_replaced(
1107 ModestHeaderViewObserver *observer,
1108 GtkTreeModel *model,
1109 const gchar *tny_folder_id){
1110 ModestMsgViewWindowPrivate *priv = NULL;
1111 ModestMsgViewWindow *window = NULL;
1113 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1114 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1116 window = MODEST_MSG_VIEW_WINDOW(observer);
1117 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1119 /* If there is an other folder in the header-view then we do
1120 * not care about it's model (msg list). Else if the
1121 * header-view shows the folder the msg shown by us is in, we
1122 * shall replace our model reference and make some check. */
1123 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1126 /* Model is changed(replaced), so we should forget the old
1127 * one. Because there might be other references and there
1128 * might be some change on the model even if we unreferenced
1129 * it, we need to disconnect our signals here. */
1130 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1131 priv->row_changed_handler))
1132 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1133 priv->row_changed_handler);
1134 priv->row_changed_handler = 0;
1135 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1136 priv->row_deleted_handler))
1137 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1138 priv->row_deleted_handler);
1139 priv->row_deleted_handler = 0;
1140 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1141 priv->row_inserted_handler))
1142 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1143 priv->row_inserted_handler);
1144 priv->row_inserted_handler = 0;
1145 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1146 priv->rows_reordered_handler))
1147 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1148 priv->rows_reordered_handler);
1149 priv->rows_reordered_handler = 0;
1150 g_object_unref(priv->header_model);
1151 priv->header_model = NULL;
1152 if (priv->row_reference)
1153 gtk_tree_row_reference_free (priv->row_reference);
1154 priv->row_reference = NULL;
1155 if (priv->next_row_reference)
1156 gtk_tree_row_reference_free (priv->next_row_reference);
1157 priv->next_row_reference = NULL;
1159 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1161 g_assert(model != NULL);
1163 /* Also we must connect to the new model for row insertions.
1164 * Only for insertions now. We will need other ones only after
1165 * the msg is show by msg-view is added to the new model. */
1166 priv->row_inserted_handler = g_signal_connect (
1167 model, "row-inserted",
1168 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1173 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1175 ModestMsgViewWindowPrivate *priv= NULL;
1177 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1178 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1180 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1184 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1186 ModestMsgViewWindowPrivate *priv= NULL;
1188 TnyHeader *header = NULL;
1189 GtkTreePath *path = NULL;
1192 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1193 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1195 /* If the message was not obtained from a treemodel,
1196 * for instance if it was opened directly by the search UI:
1198 if (priv->header_model == NULL ||
1199 priv->row_reference == NULL ||
1200 !gtk_tree_row_reference_valid (priv->row_reference)) {
1201 msg = modest_msg_view_window_get_message (self);
1203 header = tny_msg_get_header (msg);
1204 g_object_unref (msg);
1209 /* Get iter of the currently selected message in the header view: */
1210 path = gtk_tree_row_reference_get_path (priv->row_reference);
1211 g_return_val_if_fail (path != NULL, NULL);
1212 gtk_tree_model_get_iter (priv->header_model,
1216 /* Get current message header */
1217 gtk_tree_model_get (priv->header_model, &iter,
1218 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1221 gtk_tree_path_free (path);
1226 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1228 ModestMsgViewWindowPrivate *priv;
1230 g_return_val_if_fail (self, NULL);
1232 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1234 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1238 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1240 ModestMsgViewWindowPrivate *priv;
1242 g_return_val_if_fail (self, NULL);
1244 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1246 return (const gchar*) priv->msg_uid;
1250 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1253 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1254 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1255 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1259 is_active = gtk_toggle_action_get_active (toggle);
1262 gtk_widget_show (priv->find_toolbar);
1263 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1265 gtk_widget_hide (priv->find_toolbar);
1268 /* update the toggle buttons status */
1269 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1270 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1271 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1272 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1277 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1278 ModestMsgViewWindow *obj)
1280 GtkToggleAction *toggle;
1281 ModestWindowPrivate *parent_priv;
1282 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1284 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1285 gtk_toggle_action_set_active (toggle, FALSE);
1289 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1290 ModestMsgViewWindow *obj)
1292 gchar *current_search;
1293 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1295 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1296 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1300 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1302 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1303 g_free (current_search);
1304 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1308 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1310 g_free (priv->last_search);
1311 priv->last_search = g_strdup (current_search);
1312 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1315 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1316 g_free (priv->last_search);
1317 priv->last_search = NULL;
1319 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1322 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1323 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1324 g_free (priv->last_search);
1325 priv->last_search = NULL;
1327 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1331 g_free (current_search);
1336 modest_msg_view_window_set_zoom (ModestWindow *window,
1339 ModestMsgViewWindowPrivate *priv;
1340 ModestWindowPrivate *parent_priv;
1341 GtkAction *action = NULL;
1342 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1344 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1346 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1347 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1348 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1350 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1351 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1353 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1357 modest_msg_view_window_get_zoom (ModestWindow *window)
1359 ModestMsgViewWindowPrivate *priv;
1361 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1363 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1364 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1368 modest_msg_view_window_zoom_plus (ModestWindow *window)
1370 ModestWindowPrivate *parent_priv;
1371 GtkRadioAction *zoom_radio_action;
1372 GSList *group, *node;
1374 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1375 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1376 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1378 group = gtk_radio_action_get_group (zoom_radio_action);
1380 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1381 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1385 for (node = group; node != NULL; node = g_slist_next (node)) {
1386 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1387 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1395 modest_msg_view_window_zoom_minus (ModestWindow *window)
1397 ModestWindowPrivate *parent_priv;
1398 GtkRadioAction *zoom_radio_action;
1399 GSList *group, *node;
1401 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1402 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1403 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1405 group = gtk_radio_action_get_group (zoom_radio_action);
1407 for (node = group; node != NULL; node = g_slist_next (node)) {
1408 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1409 if (node->next != NULL) {
1410 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1413 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1423 modest_msg_view_window_key_event (GtkWidget *window,
1429 focus = gtk_window_get_focus (GTK_WINDOW (window));
1431 /* for the find toolbar case */
1432 if (focus && GTK_IS_ENTRY (focus)) {
1433 if (event->keyval == GDK_BackSpace) {
1435 copy = gdk_event_copy ((GdkEvent *) event);
1436 gtk_widget_event (focus, copy);
1437 gdk_event_free (copy);
1442 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1443 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1444 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1445 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1446 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1447 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1448 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1449 gboolean return_value;
1451 if (event->type == GDK_KEY_RELEASE) {
1452 GtkScrollType scroll_type;
1454 switch (event->keyval) {
1457 scroll_type = GTK_SCROLL_STEP_UP; break;
1460 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1462 case GDK_KP_Page_Up:
1463 scroll_type = GTK_SCROLL_PAGE_UP; break;
1465 case GDK_KP_Page_Down:
1466 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1469 scroll_type = GTK_SCROLL_START; break;
1472 scroll_type = GTK_SCROLL_END; break;
1473 default: scroll_type = GTK_SCROLL_NONE;
1476 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1477 scroll_type, FALSE, &return_value);
1488 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1491 ModestMsgViewWindowPrivate *priv;
1492 GtkTreeIter tmp_iter;
1493 gboolean is_last_selected;
1495 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1496 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1498 /*if no model (so no rows at all), then virtually we are the last*/
1499 if (!priv->header_model || !priv->row_reference)
1502 path = gtk_tree_row_reference_get_path (priv->row_reference);
1506 is_last_selected = TRUE;
1507 while (is_last_selected) {
1509 gtk_tree_path_next (path);
1510 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1512 gtk_tree_model_get (priv->header_model, &tmp_iter,
1513 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1516 if (msg_is_visible (header, priv->is_outbox))
1517 is_last_selected = FALSE;
1518 g_object_unref(G_OBJECT(header));
1521 gtk_tree_path_free (path);
1522 return is_last_selected;
1526 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1528 ModestMsgViewWindowPrivate *priv;
1530 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1531 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1533 return priv->header_model != NULL;
1537 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1539 ModestMsgViewWindowPrivate *priv;
1541 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1542 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1544 return priv->is_search_result;
1548 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1550 return (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) &&
1551 ( (!check_outbox) || (modest_tny_all_send_queues_get_msg_status (header) != MODEST_TNY_SEND_QUEUE_FAILED)) ;
1556 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1559 ModestMsgViewWindowPrivate *priv;
1560 gboolean is_first_selected;
1561 GtkTreeIter tmp_iter;
1562 /* gchar * path_string;*/
1564 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1565 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1567 /*if no model (so no rows at all), then virtually we are the first*/
1568 if (!priv->header_model || !priv->row_reference)
1571 path = gtk_tree_row_reference_get_path (priv->row_reference);
1575 /* path_string = gtk_tree_path_to_string (path);
1576 is_first_selected = strcmp (path_string, "0");
1578 g_free (path_string);
1579 gtk_tree_path_free (path);
1581 return is_first_selected;*/
1583 is_first_selected = TRUE;
1584 while (is_first_selected) {
1586 if(!gtk_tree_path_prev (path))
1588 /* Here the 'if' is needless for logic, but let make sure
1589 * iter is valid for gtk_tree_model_get. */
1590 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1592 gtk_tree_model_get (priv->header_model, &tmp_iter,
1593 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1596 if (msg_is_visible (header, priv->is_outbox))
1597 is_first_selected = FALSE;
1598 g_object_unref(G_OBJECT(header));
1601 gtk_tree_path_free (path);
1602 return is_first_selected;
1607 GtkTreeRowReference *row_reference;
1611 message_reader_performer (gboolean canceled,
1613 GtkWindow *parent_window,
1614 TnyAccount *account,
1617 ModestMailOperation *mail_op = NULL;
1618 MsgReaderInfo *info;
1620 info = (MsgReaderInfo *) user_data;
1621 if (canceled || err) {
1625 /* New mail operation */
1626 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(parent_window),
1627 modest_ui_actions_disk_operations_error_handler,
1630 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1631 modest_mail_operation_get_msg (mail_op, info->header, view_msg_cb, info->row_reference);
1632 g_object_unref (mail_op);
1635 /* Frees. The row_reference will be freed by the view_msg_cb callback */
1636 g_object_unref (info->header);
1637 g_slice_free (MsgReaderInfo, info);
1642 * Reads the message whose summary item is @header. It takes care of
1643 * several things, among others:
1645 * If the message was not previously downloaded then ask the user
1646 * before downloading. If there is no connection launch the connection
1647 * dialog. Update toolbar dimming rules.
1649 * Returns: TRUE if the mail operation was started, otherwise if the
1650 * user do not want to download the message, or if the user do not
1651 * want to connect, then the operation is not issued
1654 message_reader (ModestMsgViewWindow *window,
1655 ModestMsgViewWindowPrivate *priv,
1657 GtkTreeRowReference *row_reference)
1659 gboolean already_showing = FALSE;
1660 ModestWindow *msg_window = NULL;
1661 ModestWindowMgr *mgr;
1662 TnyAccount *account;
1664 MsgReaderInfo *info;
1666 g_return_val_if_fail (row_reference != NULL, FALSE);
1668 mgr = modest_runtime_get_window_mgr ();
1669 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1670 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1673 gtk_window_present (GTK_WINDOW (msg_window));
1674 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1678 /* Msg download completed */
1679 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1680 /* Ask the user if he wants to download the message if
1682 if (!tny_device_is_online (modest_runtime_get_device())) {
1683 GtkResponseType response;
1685 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1686 _("mcen_nc_get_msg"));
1687 if (response == GTK_RESPONSE_CANCEL)
1690 folder = tny_header_get_folder (header);
1691 info = g_slice_new (MsgReaderInfo);
1692 info->header = g_object_ref (header);
1693 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1695 /* Offer the connection dialog if necessary */
1696 modest_platform_connect_if_remote_and_perform ((GtkWindow *) window,
1698 TNY_FOLDER_STORE (folder),
1699 message_reader_performer,
1701 g_object_unref (folder);
1706 folder = tny_header_get_folder (header);
1707 account = tny_folder_get_account (folder);
1708 info = g_slice_new (MsgReaderInfo);
1709 info->header = g_object_ref (header);
1710 info->row_reference = gtk_tree_row_reference_copy (row_reference);
1712 message_reader_performer (FALSE, NULL, (GtkWindow *) window, account, info);
1713 g_object_unref (account);
1714 g_object_unref (folder);
1720 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1722 ModestMsgViewWindowPrivate *priv;
1723 GtkTreePath *path= NULL;
1724 GtkTreeIter tmp_iter;
1726 gboolean retval = TRUE;
1727 GtkTreeRowReference *row_reference = NULL;
1729 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1730 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1732 if (!priv->row_reference)
1735 /* Update the next row reference if it's not valid. This could
1736 happen if for example the header which it was pointing to,
1737 was deleted. The best place to do it is in the row-deleted
1738 handler but the tinymail model do not work like the glib
1739 tree models and reports the deletion when the row is still
1741 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1742 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1743 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1744 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1747 if (priv->next_row_reference)
1748 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1752 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1754 gtk_tree_model_get_iter (priv->header_model,
1757 gtk_tree_path_free (path);
1759 gtk_tree_model_get (priv->header_model, &tmp_iter,
1760 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1763 /* Read the message & show it */
1764 if (!message_reader (window, priv, header, row_reference)) {
1767 gtk_tree_row_reference_free (row_reference);
1770 g_object_unref (header);
1776 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1778 ModestMsgViewWindowPrivate *priv = NULL;
1780 gboolean finished = FALSE;
1781 gboolean retval = FALSE;
1783 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1784 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1786 /* Return inmediatly if there is no header model */
1787 if (!priv->header_model || !priv->row_reference)
1790 path = gtk_tree_row_reference_get_path (priv->row_reference);
1791 while (!finished && gtk_tree_path_prev (path)) {
1795 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1796 gtk_tree_model_get (priv->header_model, &iter,
1797 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1801 if (msg_is_visible (header, priv->is_outbox)) {
1802 GtkTreeRowReference *row_reference;
1803 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1804 /* Read the message & show it */
1805 retval = message_reader (window, priv, header, row_reference);
1806 gtk_tree_row_reference_free (row_reference);
1810 g_object_unref (header);
1814 gtk_tree_path_free (path);
1819 view_msg_cb (ModestMailOperation *mail_op,
1826 ModestMsgViewWindow *self = NULL;
1827 ModestMsgViewWindowPrivate *priv = NULL;
1828 GtkTreeRowReference *row_reference = NULL;
1830 row_reference = (GtkTreeRowReference *) user_data;
1832 gtk_tree_row_reference_free (row_reference);
1836 /* If there was any error */
1837 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1838 gtk_tree_row_reference_free (row_reference);
1842 /* Get the window */
1843 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1844 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1845 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1847 /* Update the row reference */
1848 if (priv->row_reference != NULL) {
1849 gtk_tree_row_reference_free (priv->row_reference);
1850 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1851 if (priv->next_row_reference != NULL) {
1852 gtk_tree_row_reference_free (priv->next_row_reference);
1854 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1855 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1858 /* Mark header as read */
1859 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1860 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1862 /* Set new message */
1863 if (priv->msg_view != NULL && TNY_IS_MSG_VIEW (priv->msg_view)) {
1864 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1865 modest_msg_view_window_update_priority (self);
1866 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1867 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1870 /* Set the new message uid of the window */
1871 if (priv->msg_uid) {
1872 g_free (priv->msg_uid);
1873 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1876 /* Notify the observers */
1877 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1878 0, priv->header_model, priv->row_reference);
1881 g_object_unref (self);
1882 gtk_tree_row_reference_free (row_reference);
1886 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1888 ModestMsgViewWindowPrivate *priv;
1890 TnyFolderType folder_type;
1892 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1894 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1896 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1900 folder = tny_msg_get_folder (msg);
1902 folder_type = modest_tny_folder_guess_folder_type (folder);
1903 g_object_unref (folder);
1905 g_object_unref (msg);
1913 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1915 ModestMsgViewWindowPrivate *priv;
1916 TnyHeader *header = NULL;
1917 TnyHeaderFlags flags = 0;
1919 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1921 if (priv->header_model && priv->row_reference) {
1923 GtkTreePath *path = NULL;
1925 path = gtk_tree_row_reference_get_path (priv->row_reference);
1926 g_return_if_fail (path != NULL);
1927 gtk_tree_model_get_iter (priv->header_model,
1929 gtk_tree_row_reference_get_path (priv->row_reference));
1931 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1933 gtk_tree_path_free (path);
1936 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1938 header = tny_msg_get_header (msg);
1939 g_object_unref (msg);
1944 flags = tny_header_get_flags (header);
1945 g_object_unref(G_OBJECT(header));
1948 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1953 toolbar_resize (ModestMsgViewWindow *self)
1955 ModestMsgViewWindowPrivate *priv = NULL;
1956 ModestWindowPrivate *parent_priv = NULL;
1958 gint static_button_size;
1959 ModestWindowMgr *mgr;
1961 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1962 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1963 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1965 mgr = modest_runtime_get_window_mgr ();
1966 static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1968 if (parent_priv->toolbar) {
1969 /* left size buttons */
1970 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1971 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1972 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1973 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1974 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo");
1975 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1976 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1977 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1978 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1979 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1980 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1981 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1982 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1983 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1984 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1985 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1987 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1988 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1989 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1990 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1991 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
1992 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->next_toolitem), TRUE);
1993 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
1994 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->prev_toolitem), TRUE);
2000 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
2002 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
2003 ModestWindowPrivate *parent_priv;
2004 ModestWindowMgr *mgr;
2005 gboolean is_fullscreen;
2006 GtkAction *fs_toggle_action;
2009 mgr = modest_runtime_get_window_mgr ();
2010 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
2012 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
2014 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
2015 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
2016 if (is_fullscreen != active) {
2017 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
2019 toolbar_resize (MODEST_MSG_VIEW_WINDOW (widget));
2027 modest_msg_view_window_show_toolbar (ModestWindow *self,
2028 gboolean show_toolbar)
2030 ModestMsgViewWindowPrivate *priv = NULL;
2031 ModestWindowPrivate *parent_priv;
2032 GtkWidget *reply_button = NULL, *menu = NULL;
2033 GtkWidget *placeholder = NULL;
2035 const gchar *action_name;
2038 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2039 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2041 /* Set optimized view status */
2042 priv->optimized_view = !show_toolbar;
2044 if (!parent_priv->toolbar) {
2045 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2047 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2049 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
2050 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2051 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2052 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2053 toolbar_resize (MODEST_MSG_VIEW_WINDOW (self));
2055 /* Add ProgressBar (Transfer toolbar) */
2056 priv->progress_bar = modest_progress_bar_new ();
2057 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
2058 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
2059 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
2060 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
2061 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
2063 /* Connect cancel 'clicked' signal to abort progress mode */
2064 g_signal_connect(priv->cancel_toolitem, "clicked",
2065 G_CALLBACK(cancel_progressbar),
2068 /* Add it to the observers list */
2069 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
2072 hildon_window_add_toolbar (HILDON_WINDOW (self),
2073 GTK_TOOLBAR (parent_priv->toolbar));
2075 /* Set reply button tap and hold menu */
2076 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2077 "/ToolBar/ToolbarMessageReply");
2078 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2079 "/ToolbarReplyCSM");
2080 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2084 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2085 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2086 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2088 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2089 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2090 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2092 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2095 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2096 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2099 /* Update also the actions (to update the toggles in the
2100 menus), we have to do it manually because some other window
2101 of the same time could have changed it (remember that the
2102 toolbar fullscreen mode is shared by all the windows of the
2104 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2105 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2107 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2109 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2110 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2115 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2117 ModestMsgViewWindow *window)
2119 if (!GTK_WIDGET_VISIBLE (window))
2122 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), MODEST_DIMMING_RULES_CLIPBOARD);
2126 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2128 ModestMsgViewWindowPrivate *priv;
2130 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2131 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2133 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2137 cancel_progressbar (GtkToolButton *toolbutton,
2138 ModestMsgViewWindow *self)
2141 ModestMsgViewWindowPrivate *priv;
2143 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2145 /* Get operation observers and cancel its current operation */
2146 tmp = priv->progress_widgets;
2148 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2149 tmp=g_slist_next(tmp);
2153 observers_empty (ModestMsgViewWindow *self)
2156 ModestMsgViewWindowPrivate *priv;
2157 gboolean is_empty = TRUE;
2158 guint pending_ops = 0;
2160 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2161 tmp = priv->progress_widgets;
2163 /* Check all observers */
2164 while (tmp && is_empty) {
2165 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2166 is_empty = pending_ops == 0;
2168 tmp = g_slist_next(tmp);
2175 on_account_removed (TnyAccountStore *account_store,
2176 TnyAccount *account,
2179 /* Do nothing if it's a transport account, because we only
2180 show the messages of a store account */
2181 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2182 const gchar *parent_acc = NULL;
2183 const gchar *our_acc = NULL;
2185 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2186 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2188 /* Close this window if I'm showing a message of the removed account */
2189 if (strcmp (parent_acc, our_acc) == 0)
2190 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2195 on_mail_operation_started (ModestMailOperation *mail_op,
2198 ModestMsgViewWindow *self;
2199 ModestMailOperationTypeOperation op_type;
2201 ModestMsgViewWindowPrivate *priv;
2202 GObject *source = NULL;
2204 self = MODEST_MSG_VIEW_WINDOW (user_data);
2205 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2206 op_type = modest_mail_operation_get_type_operation (mail_op);
2207 tmp = priv->progress_widgets;
2208 source = modest_mail_operation_get_source(mail_op);
2209 if (G_OBJECT (self) == source) {
2210 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2211 set_toolbar_transfer_mode(self);
2213 modest_progress_object_add_operation (
2214 MODEST_PROGRESS_OBJECT (tmp->data),
2216 tmp = g_slist_next (tmp);
2220 g_object_unref (source);
2224 on_mail_operation_finished (ModestMailOperation *mail_op,
2227 ModestMsgViewWindow *self;
2228 ModestMailOperationTypeOperation op_type;
2230 ModestMsgViewWindowPrivate *priv;
2232 self = MODEST_MSG_VIEW_WINDOW (user_data);
2233 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2234 op_type = modest_mail_operation_get_type_operation (mail_op);
2235 tmp = priv->progress_widgets;
2237 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2239 modest_progress_object_remove_operation (
2240 MODEST_PROGRESS_OBJECT (tmp->data),
2242 tmp = g_slist_next (tmp);
2245 /* If no more operations are being observed, NORMAL mode is enabled again */
2246 if (observers_empty (self)) {
2247 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2250 /* Update dimming rules. We have to do this right here
2251 and not in view_msg_cb because at that point the
2252 transfer mode is still enabled so the dimming rule
2253 won't let the user delete the message that has been
2254 readed for example */
2255 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2256 modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2261 on_queue_changed (ModestMailOperationQueue *queue,
2262 ModestMailOperation *mail_op,
2263 ModestMailOperationQueueNotification type,
2264 ModestMsgViewWindow *self)
2266 ModestMsgViewWindowPrivate *priv;
2268 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2270 /* If this operations was created by another window, do nothing */
2271 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2274 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2275 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2277 "operation-started",
2278 G_CALLBACK (on_mail_operation_started),
2280 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2282 "operation-finished",
2283 G_CALLBACK (on_mail_operation_finished),
2285 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2286 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2288 "operation-started");
2289 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2291 "operation-finished");
2296 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2298 ModestMsgViewWindowPrivate *priv;
2299 TnyList *selected_attachments = NULL;
2301 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2302 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2304 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2306 return selected_attachments;
2310 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2312 ModestMsgViewWindowPrivate *priv;
2313 const gchar *msg_uid;
2314 gchar *attachment_uid = NULL;
2315 gint attachment_index = 0;
2316 TnyList *attachments;
2318 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2319 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2320 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2322 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2323 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2324 attachment_index = modest_list_index (attachments, (GObject *) mime_part);
2325 g_object_unref (attachments);
2327 if (msg_uid && attachment_index >= 0) {
2328 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2331 if (mime_part == NULL) {
2332 gboolean error = FALSE;
2333 TnyList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2334 if (selected_attachments == NULL || tny_list_get_length (selected_attachments) == 0) {
2336 } else if (tny_list_get_length (selected_attachments) > 1) {
2337 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2341 iter = tny_list_create_iterator (selected_attachments);
2342 mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2343 g_object_unref (iter);
2345 g_object_unref (selected_attachments);
2350 g_object_ref (mime_part);
2353 if (tny_mime_part_is_purged (mime_part)) {
2354 g_object_unref (mime_part);
2358 if (!modest_tny_mime_part_is_msg (mime_part)) {
2359 gchar *filepath = NULL;
2360 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2361 const gchar *content_type;
2362 gboolean show_error_banner = FALSE;
2364 TnyFsStream *temp_stream = NULL;
2365 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2368 if (temp_stream != NULL) {
2369 content_type = tny_mime_part_get_content_type (mime_part);
2370 if (tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream), &err) >= 0) {
2371 /* make the file read-only */
2372 if (g_chmod(filepath, 0444) != 0)
2373 g_warning ("%s: failed to set file '%s' to read-only: %s",
2374 __FUNCTION__, filepath, strerror(errno));
2376 modest_platform_activate_file (filepath, content_type);
2378 /* error while saving attachment, maybe cerm_device_memory_full */
2379 show_error_banner = TRUE;
2381 g_warning ("%s: tny_mime_part_decode_to_stream failed (%s)", __FUNCTION__, err->message);
2385 g_object_unref (temp_stream);
2387 /* NOTE: files in the temporary area will be automatically
2388 * cleaned after some time if they are no longer in use */
2390 if (filepath != NULL) {
2391 /* the file may already exist but it isn't writable,
2392 * let's try to open it anyway */
2393 content_type = tny_mime_part_get_content_type (mime_part);
2394 modest_platform_activate_file (filepath, content_type);
2397 g_warning ("%s: modest_utils_create_temp_stream failed", __FUNCTION__);
2398 show_error_banner = TRUE;
2401 if (show_error_banner)
2402 modest_platform_information_banner (NULL, NULL, _("mail_ib_file_operation_failed"));
2404 /* message attachment */
2405 TnyHeader *header = NULL;
2406 ModestWindowMgr *mgr;
2407 ModestWindow *msg_win = NULL;
2410 header = tny_msg_get_header (TNY_MSG (mime_part));
2411 mgr = modest_runtime_get_window_mgr ();
2412 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2415 if (msg_win) /* there is already a window for this uid; top it */
2416 gtk_window_present (GTK_WINDOW(msg_win));
2418 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2419 * thus, we don't do anything */
2420 g_warning ("window for is already being created");
2422 /* it's not found, so create a new window for it */
2423 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2424 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2426 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2427 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2428 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2429 modest_window_get_zoom (MODEST_WINDOW (window)));
2430 modest_window_mgr_register_window (mgr, msg_win);
2431 gtk_widget_show_all (GTK_WIDGET (msg_win));
2434 g_object_unref (mime_part);
2447 GnomeVFSResult result;
2450 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2451 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2452 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2453 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2456 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2460 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2461 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2462 g_free (pair->filename);
2463 g_object_unref (pair->part);
2464 g_slice_free (SaveMimePartPair, pair);
2466 g_list_free (info->pairs);
2469 gtk_widget_destroy (info->banner);
2470 g_slice_free (SaveMimePartInfo, info);
2475 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2477 if (info->pairs != NULL) {
2478 save_mime_part_to_file (info);
2480 /* This is a GDK lock because we are an idle callback and
2481 * hildon_banner_show_information is or does Gtk+ code */
2483 gdk_threads_enter (); /* CHECKED */
2484 save_mime_part_info_free (info, TRUE);
2485 if (info->result == GNOME_VFS_OK) {
2486 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2487 } else if (info->result == GNOME_VFS_ERROR_NO_SPACE) {
2488 hildon_banner_show_information (NULL, NULL, dgettext("ke-recv",
2489 "cerm_device_memory_full"));
2491 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2493 gdk_threads_leave (); /* CHECKED */
2500 save_mime_part_to_file (SaveMimePartInfo *info)
2502 GnomeVFSHandle *handle;
2504 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2506 info->result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2507 if (info->result == GNOME_VFS_OK) {
2508 stream = tny_vfs_stream_new (handle);
2509 if (tny_mime_part_decode_to_stream (pair->part, stream, NULL) < 0) {
2510 info->result = GNOME_VFS_ERROR_IO;
2512 g_object_unref (G_OBJECT (stream));
2513 g_object_unref (pair->part);
2514 g_slice_free (SaveMimePartPair, pair);
2515 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2517 save_mime_part_info_free (info, FALSE);
2520 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2525 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2527 gboolean is_ok = TRUE;
2528 gint replaced_files = 0;
2529 const GList *files = info->pairs;
2532 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2533 SaveMimePartPair *pair = iter->data;
2534 if (modest_utils_file_exists (pair->filename)) {
2538 if (replaced_files) {
2539 GtkWidget *confirm_overwrite_dialog;
2540 const gchar *message = (replaced_files == 1) ?
2541 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2542 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2543 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2546 gtk_widget_destroy (confirm_overwrite_dialog);
2550 save_mime_part_info_free (info, TRUE);
2552 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2553 _CS("sfil_ib_saving"));
2554 info->banner = banner;
2555 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2562 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, TnyList *mime_parts)
2564 ModestMsgViewWindowPrivate *priv;
2565 GList *files_to_save = NULL;
2566 GtkWidget *save_dialog = NULL;
2567 gchar *folder = NULL;
2568 const gchar *filename = NULL;
2569 gchar *save_multiple_str = NULL;
2571 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2572 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2574 if (mime_parts == NULL) {
2575 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2576 if (mime_parts == NULL || tny_list_get_length (mime_parts) == 0)
2579 g_object_ref (mime_parts);
2582 /* prepare dialog */
2583 if (tny_list_get_length (mime_parts) == 1) {
2585 /* only one attachment selected */
2586 iter = tny_list_create_iterator (mime_parts);
2587 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2588 g_object_unref (iter);
2589 if (!modest_tny_mime_part_is_msg (mime_part) &&
2590 modest_tny_mime_part_is_attachment_for_modest (mime_part) &&
2591 !tny_mime_part_is_purged (mime_part)) {
2592 filename = tny_mime_part_get_filename (mime_part);
2594 /* TODO: show any error? */
2595 g_warning ("Tried to save a non-file attachment");
2596 g_object_unref (mime_parts);
2599 g_object_unref (mime_part);
2601 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2602 tny_list_get_length (mime_parts));
2605 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2606 GTK_FILE_CHOOSER_ACTION_SAVE);
2609 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2610 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2614 if (filename != NULL)
2615 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2618 /* if multiple, set multiple string */
2619 if (save_multiple_str) {
2620 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2621 gtk_window_set_title (GTK_WINDOW (save_dialog), _FM("sfil_ti_save_objects_files"));
2625 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2626 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2628 if (!modest_utils_folder_writable (chooser_uri)) {
2629 hildon_banner_show_information
2630 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2634 iter = tny_list_create_iterator (mime_parts);
2635 while (!tny_iterator_is_done (iter)) {
2636 TnyMimePart *mime_part = (TnyMimePart *) tny_iterator_get_current (iter);
2638 if ((modest_tny_mime_part_is_attachment_for_modest (mime_part)) &&
2639 !tny_mime_part_is_purged (mime_part) &&
2640 (tny_mime_part_get_filename (mime_part) != NULL)) {
2641 SaveMimePartPair *pair;
2643 pair = g_slice_new0 (SaveMimePartPair);
2644 if (save_multiple_str) {
2646 g_build_filename (chooser_uri,
2647 tny_mime_part_get_filename (mime_part), NULL);
2649 pair->filename = g_strdup (chooser_uri);
2651 pair->part = mime_part;
2652 files_to_save = g_list_prepend (files_to_save, pair);
2654 tny_iterator_next (iter);
2656 g_object_unref (iter);
2658 g_free (chooser_uri);
2661 gtk_widget_destroy (save_dialog);
2663 g_object_unref (mime_parts);
2665 if (files_to_save != NULL) {
2666 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2667 info->pairs = files_to_save;
2668 info->result = TRUE;
2669 save_mime_parts_to_file_with_checks (info);
2674 show_remove_attachment_information (gpointer userdata)
2676 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2677 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2679 /* We're outside the main lock */
2680 gdk_threads_enter ();
2682 if (priv->remove_attachment_banner != NULL) {
2683 gtk_widget_destroy (priv->remove_attachment_banner);
2684 g_object_unref (priv->remove_attachment_banner);
2687 priv->remove_attachment_banner = g_object_ref (
2688 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2690 gdk_threads_leave ();
2696 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2698 ModestMsgViewWindowPrivate *priv;
2699 TnyList *mime_parts = NULL;
2700 gchar *confirmation_message;
2705 /* TnyFolder *folder; */
2707 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2708 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2711 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2713 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2715 /* Remove already purged messages from mime parts list */
2716 iter = tny_list_create_iterator (mime_parts);
2717 while (!tny_iterator_is_done (iter)) {
2718 TnyMimePart *part = TNY_MIME_PART (tny_iterator_get_current (iter));
2719 tny_iterator_next (iter);
2720 if (tny_mime_part_is_purged (part)) {
2721 tny_list_remove (mime_parts, (GObject *) part);
2723 g_object_unref (part);
2725 g_object_unref (iter);
2727 if (tny_list_get_length (mime_parts) == 0) {
2728 g_object_unref (mime_parts);
2732 n_attachments = tny_list_get_length (mime_parts);
2733 if (n_attachments == 1) {
2734 const gchar *filename;
2737 iter = tny_list_create_iterator (mime_parts);
2738 part = (TnyMimePart *) tny_iterator_get_current (iter);
2739 g_object_unref (iter);
2740 if (modest_tny_mime_part_is_msg (part)) {
2742 header = tny_msg_get_header (TNY_MSG (part));
2743 filename = tny_header_get_subject (header);
2744 g_object_unref (header);
2745 if (filename == NULL)
2746 filename = _("mail_va_no_subject");
2748 filename = tny_mime_part_get_filename (TNY_MIME_PART (part));
2750 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2751 g_object_unref (part);
2753 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2754 "mcen_nc_purge_files_text",
2755 n_attachments), n_attachments);
2757 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2758 confirmation_message);
2759 g_free (confirmation_message);
2761 if (response != GTK_RESPONSE_OK) {
2762 g_object_unref (mime_parts);
2766 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2767 /* folder = tny_msg_get_folder (msg); */
2768 /* tny_msg_uncache_attachments (msg); */
2769 /* tny_folder_refresh (folder, NULL); */
2770 /* g_object_unref (folder); */
2772 iter = tny_list_create_iterator (mime_parts);
2773 while (!tny_iterator_is_done (iter)) {
2776 part = (TnyMimePart *) tny_iterator_get_current (iter);
2777 tny_mime_part_set_purged (TNY_MIME_PART (part));
2778 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2779 g_object_unref (part);
2780 tny_iterator_next (iter);
2782 g_object_unref (iter);
2784 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2785 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2786 tny_msg_rewrite_cache (msg);
2787 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2788 g_object_unref (msg);
2790 g_object_unref (mime_parts);
2792 if (priv->purge_timeout > 0) {
2793 g_source_remove (priv->purge_timeout);
2794 priv->purge_timeout = 0;
2797 if (priv->remove_attachment_banner) {
2798 gtk_widget_destroy (priv->remove_attachment_banner);
2799 g_object_unref (priv->remove_attachment_banner);
2800 priv->remove_attachment_banner = NULL;
2808 update_window_title (ModestMsgViewWindow *window)
2810 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2812 TnyHeader *header = NULL;
2813 const gchar *subject = NULL;
2815 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2818 header = tny_msg_get_header (msg);
2819 subject = tny_header_get_subject (header);
2820 g_object_unref (msg);
2823 if ((subject == NULL)||(subject[0] == '\0'))
2824 subject = _("mail_va_no_subject");
2826 gtk_window_set_title (GTK_WINDOW (window), subject);
2830 static void on_move_focus (GtkWidget *widget,
2831 GtkDirectionType direction,
2834 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");