1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <glib/gi18n.h>
31 #include <tny-account-store.h>
32 #include <tny-simple-list.h>
34 #include <tny-mime-part.h>
35 #include <tny-vfs-stream.h>
36 #include "modest-marshal.h"
37 #include "modest-platform.h"
38 #include <modest-utils.h>
39 #include <modest-maemo-utils.h>
40 #include <modest-tny-msg.h>
41 #include <modest-msg-view-window.h>
42 #include <modest-attachments-view.h>
43 #include <modest-main-window-ui.h>
44 #include "modest-msg-view-window-ui-dimming.h"
45 #include <modest-widget-memory.h>
46 #include <modest-runtime.h>
47 #include <modest-window-priv.h>
48 #include <modest-tny-folder.h>
49 #include <modest-text-utils.h>
50 #include <modest-account-mgr-helpers.h>
51 #include "modest-progress-bar-widget.h"
52 #include "modest-defs.h"
53 #include "modest-hildon-includes.h"
54 #include "modest-ui-dimming-manager.h"
55 #include <gdk/gdkkeysyms.h>
56 #include <modest-tny-account.h>
57 #include <modest-mime-part-view.h>
58 #include <modest-isearch-view.h>
61 #include <glib/gstdio.h>
63 #define DEFAULT_FOLDER "MyDocs/.documents"
65 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
66 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
67 static void modest_header_view_observer_init(
68 ModestHeaderViewObserverIface *iface_class);
69 static void modest_msg_view_window_finalize (GObject *obj);
70 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
72 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
73 ModestMsgViewWindow *obj);
74 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
75 ModestMsgViewWindow *obj);
77 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
78 static void modest_msg_view_window_set_zoom (ModestWindow *window,
80 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
81 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
82 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
83 static gboolean modest_msg_view_window_key_event (GtkWidget *window,
86 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
87 GdkEventWindowState *event,
89 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
91 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
92 gboolean show_toolbar);
94 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
96 ModestMsgViewWindow *window);
97 void modest_msg_view_window_on_row_changed(
98 GtkTreeModel *header_model,
101 ModestMsgViewWindow *window);
103 void modest_msg_view_window_on_row_deleted(
104 GtkTreeModel *header_model,
106 ModestMsgViewWindow *window);
108 void modest_msg_view_window_on_row_inserted(
109 GtkTreeModel *header_model,
110 GtkTreePath *tree_path,
111 GtkTreeIter *tree_iter,
112 ModestMsgViewWindow *window);
114 void modest_msg_view_window_on_row_reordered(
115 GtkTreeModel *header_model,
119 ModestMsgViewWindow *window);
121 void modest_msg_view_window_update_model_replaced(
122 ModestHeaderViewObserver *window,
124 const gchar *tny_folder_id);
126 static void cancel_progressbar (GtkToolButton *toolbutton,
127 ModestMsgViewWindow *self);
129 static void on_queue_changed (ModestMailOperationQueue *queue,
130 ModestMailOperation *mail_op,
131 ModestMailOperationQueueNotification type,
132 ModestMsgViewWindow *self);
134 static void on_account_removed (TnyAccountStore *account_store,
138 static void on_move_focus (GtkWidget *widget,
139 GtkDirectionType direction,
142 static void view_msg_cb (ModestMailOperation *mail_op,
149 static void set_toolbar_mode (ModestMsgViewWindow *self,
150 ModestToolBarModes mode);
152 static void update_window_title (ModestMsgViewWindow *window);
154 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
155 static void init_window (ModestMsgViewWindow *obj);
157 static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox);
160 /* list my signals */
166 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
167 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
168 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
171 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
172 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
173 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
174 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
175 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
176 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
177 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
180 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
181 struct _ModestMsgViewWindowPrivate {
184 GtkWidget *main_scroll;
185 GtkWidget *find_toolbar;
188 /* Progress observers */
189 GtkWidget *progress_bar;
190 GSList *progress_widgets;
193 GtkWidget *progress_toolitem;
194 GtkWidget *cancel_toolitem;
195 GtkWidget *prev_toolitem;
196 GtkWidget *next_toolitem;
197 ModestToolBarModes current_toolbar_mode;
199 /* Optimized view enabled */
200 gboolean optimized_view;
202 /* Whether this was created via the *_new_for_search_result() function. */
203 gboolean is_search_result;
205 /* Whether the message is in outbox */
208 /* A reference to the @model of the header view
209 * to allow selecting previous/next messages,
210 * if the message is currently selected in the header view.
212 const gchar *header_folder_id;
213 GtkTreeModel *header_model;
214 GtkTreeRowReference *row_reference;
215 GtkTreeRowReference *next_row_reference;
217 gulong clipboard_change_handler;
218 gulong queue_change_handler;
219 gulong account_removed_handler;
220 gulong row_changed_handler;
221 gulong row_deleted_handler;
222 gulong row_inserted_handler;
223 gulong rows_reordered_handler;
226 GtkWidget *remove_attachment_banner;
228 guint progress_bar_timeout;
235 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
236 MODEST_TYPE_MSG_VIEW_WINDOW, \
237 ModestMsgViewWindowPrivate))
239 static GtkWindowClass *parent_class = NULL;
241 /* uncomment the following if you have defined any signals */
242 static guint signals[LAST_SIGNAL] = {0};
245 modest_msg_view_window_get_type (void)
247 static GType my_type = 0;
249 static const GTypeInfo my_info = {
250 sizeof(ModestMsgViewWindowClass),
251 NULL, /* base init */
252 NULL, /* base finalize */
253 (GClassInitFunc) modest_msg_view_window_class_init,
254 NULL, /* class finalize */
255 NULL, /* class data */
256 sizeof(ModestMsgViewWindow),
258 (GInstanceInitFunc) modest_msg_view_window_init,
261 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
262 "ModestMsgViewWindow",
265 static const GInterfaceInfo modest_header_view_observer_info =
267 (GInterfaceInitFunc) modest_header_view_observer_init,
268 NULL, /* interface_finalize */
269 NULL /* interface_data */
272 g_type_add_interface_static (my_type,
273 MODEST_TYPE_HEADER_VIEW_OBSERVER,
274 &modest_header_view_observer_info);
280 save_state (ModestWindow *self)
282 modest_widget_memory_save (modest_runtime_get_conf (),
284 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
289 restore_settings (ModestMsgViewWindow *self)
292 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
295 conf = modest_runtime_get_conf ();
296 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
297 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
298 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
299 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
300 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
301 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
302 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
303 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
304 modest_widget_memory_restore (conf,
306 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
310 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
312 GObjectClass *gobject_class;
313 ModestWindowClass *modest_window_class;
314 gobject_class = (GObjectClass*) klass;
315 modest_window_class = (ModestWindowClass *) klass;
317 parent_class = g_type_class_peek_parent (klass);
318 gobject_class->finalize = modest_msg_view_window_finalize;
320 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
321 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
322 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
323 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
324 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
325 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
327 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
329 modest_window_class->save_state_func = save_state;
331 signals[MSG_CHANGED_SIGNAL] =
332 g_signal_new ("msg-changed",
333 G_TYPE_FROM_CLASS (gobject_class),
335 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
337 modest_marshal_VOID__POINTER_POINTER,
338 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
341 static void modest_header_view_observer_init(
342 ModestHeaderViewObserverIface *iface_class)
344 iface_class->update_func = modest_msg_view_window_update_model_replaced;
348 modest_msg_view_window_init (ModestMsgViewWindow *obj)
350 ModestMsgViewWindowPrivate *priv;
351 ModestWindowPrivate *parent_priv = NULL;
352 GtkActionGroup *action_group = NULL;
353 GError *error = NULL;
354 GdkPixbuf *window_icon;
356 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
357 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
358 parent_priv->ui_manager = gtk_ui_manager_new();
360 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
361 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
363 /* Add common actions */
364 gtk_action_group_add_actions (action_group,
365 modest_action_entries,
366 G_N_ELEMENTS (modest_action_entries),
368 gtk_action_group_add_toggle_actions (action_group,
369 modest_toggle_action_entries,
370 G_N_ELEMENTS (modest_toggle_action_entries),
372 gtk_action_group_add_toggle_actions (action_group,
373 msg_view_toggle_action_entries,
374 G_N_ELEMENTS (msg_view_toggle_action_entries),
376 gtk_action_group_add_radio_actions (action_group,
377 msg_view_zoom_action_entries,
378 G_N_ELEMENTS (msg_view_zoom_action_entries),
380 G_CALLBACK (modest_ui_actions_on_change_zoom),
383 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
384 g_object_unref (action_group);
386 /* Load the UI definition */
387 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
390 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
391 g_error_free (error);
396 /* Add accelerators */
397 gtk_window_add_accel_group (GTK_WINDOW (obj),
398 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
400 priv->is_search_result = FALSE;
401 priv->is_outbox = FALSE;
403 priv->msg_view = NULL;
404 priv->header_model = NULL;
405 priv->header_folder_id = NULL;
406 priv->clipboard_change_handler = 0;
407 priv->queue_change_handler = 0;
408 priv->account_removed_handler = 0;
409 priv->row_changed_handler = 0;
410 priv->row_deleted_handler = 0;
411 priv->row_inserted_handler = 0;
412 priv->rows_reordered_handler = 0;
413 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
415 priv->optimized_view = FALSE;
416 priv->progress_bar_timeout = 0;
417 priv->purge_timeout = 0;
418 priv->remove_attachment_banner = NULL;
419 priv->msg_uid = NULL;
421 priv->sighandlers = NULL;
424 init_window (MODEST_MSG_VIEW_WINDOW(obj));
426 /* Set window icon */
427 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON, MODEST_ICON_SIZE_BIG);
429 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
430 g_object_unref (window_icon);
433 hildon_program_add_window (hildon_program_get_instance(),
436 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
437 GTK_WINDOW(obj),"applications_email_viewer");
442 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
444 ModestMsgViewWindowPrivate *priv = NULL;
446 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
448 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
450 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
452 if (priv->progress_bar_timeout > 0) {
453 g_source_remove (priv->progress_bar_timeout);
454 priv->progress_bar_timeout = 0;
461 set_toolbar_mode (ModestMsgViewWindow *self,
462 ModestToolBarModes mode)
464 ModestWindowPrivate *parent_priv;
465 ModestMsgViewWindowPrivate *priv;
466 /* GtkWidget *widget = NULL; */
468 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
470 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
471 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
473 /* Sets current toolbar mode */
474 priv->current_toolbar_mode = mode;
476 /* Update toolbar dimming state */
477 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
480 case TOOLBAR_MODE_NORMAL:
481 if (priv->progress_toolitem) {
482 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
483 gtk_widget_hide (priv->progress_toolitem);
486 if (priv->progress_bar)
487 gtk_widget_hide (priv->progress_bar);
489 if (priv->cancel_toolitem)
490 gtk_widget_hide (priv->cancel_toolitem);
492 if (priv->prev_toolitem)
493 gtk_widget_show (priv->prev_toolitem);
495 if (priv->next_toolitem)
496 gtk_widget_show (priv->next_toolitem);
498 /* Hide toolbar if optimized view is enabled */
499 if (priv->optimized_view) {
500 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
501 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
505 case TOOLBAR_MODE_TRANSFER:
506 if (priv->prev_toolitem)
507 gtk_widget_hide (priv->prev_toolitem);
509 if (priv->next_toolitem)
510 gtk_widget_hide (priv->next_toolitem);
512 if (priv->progress_bar)
513 gtk_widget_show (priv->progress_bar);
515 if (priv->progress_toolitem) {
516 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
517 gtk_widget_show (priv->progress_toolitem);
520 if (priv->cancel_toolitem)
521 gtk_widget_show (priv->cancel_toolitem);
523 /* Show toolbar if it's hiden (optimized view ) */
524 if (priv->optimized_view) {
525 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
526 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
531 g_return_if_reached ();
538 menubar_to_menu (GtkUIManager *ui_manager)
540 GtkWidget *main_menu;
542 /* Get the menubar from the UI manager */
543 main_menu = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
549 init_window (ModestMsgViewWindow *obj)
551 GtkWidget *main_vbox;
552 ModestMsgViewWindowPrivate *priv;
553 ModestWindowPrivate *parent_priv;
555 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
556 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
558 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
559 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
560 main_vbox = gtk_vbox_new (FALSE, 6);
562 #ifdef MODEST_USE_MOZEMBED
563 priv->main_scroll = priv->msg_view;
564 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
566 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
567 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
569 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
570 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
571 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
573 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
574 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
576 priv->find_toolbar = hildon_find_toolbar_new (NULL);
577 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
578 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
580 gtk_widget_show_all (GTK_WIDGET(main_vbox));
584 modest_msg_view_window_disconnect_signals (ModestWindow *self)
586 ModestMsgViewWindowPrivate *priv;
587 ModestHeaderView *header_view = NULL;
588 ModestWindow *main_window = NULL;
590 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
592 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
593 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
594 priv->clipboard_change_handler))
595 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
596 priv->clipboard_change_handler);
598 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
599 priv->queue_change_handler))
600 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
601 priv->queue_change_handler);
603 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
604 priv->account_removed_handler))
605 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
606 priv->account_removed_handler);
608 if (priv->header_model) {
609 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
610 priv->row_changed_handler))
611 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
612 priv->row_changed_handler);
614 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
615 priv->row_deleted_handler))
616 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
617 priv->row_deleted_handler);
619 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
620 priv->row_inserted_handler))
621 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
622 priv->row_inserted_handler);
624 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
625 priv->rows_reordered_handler))
626 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
627 priv->rows_reordered_handler);
630 modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
631 priv->sighandlers = NULL;
633 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
634 FALSE); /* don't create */
638 header_view = MODEST_HEADER_VIEW(
639 modest_main_window_get_child_widget(
640 MODEST_MAIN_WINDOW(main_window),
641 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
642 if (header_view == NULL)
645 modest_header_view_remove_observer(header_view,
646 MODEST_HEADER_VIEW_OBSERVER(self));
650 modest_msg_view_window_finalize (GObject *obj)
652 ModestMsgViewWindowPrivate *priv;
654 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
656 /* Sanity check: shouldn't be needed, the window mgr should
657 call this function before */
658 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
660 if (priv->header_model != NULL) {
661 g_object_unref (priv->header_model);
662 priv->header_model = NULL;
665 if (priv->progress_bar_timeout > 0) {
666 g_source_remove (priv->progress_bar_timeout);
667 priv->progress_bar_timeout = 0;
670 if (priv->remove_attachment_banner) {
671 gtk_widget_destroy (priv->remove_attachment_banner);
672 g_object_unref (priv->remove_attachment_banner);
673 priv->remove_attachment_banner = NULL;
676 if (priv->purge_timeout > 0) {
677 g_source_remove (priv->purge_timeout);
678 priv->purge_timeout = 0;
681 if (priv->row_reference) {
682 gtk_tree_row_reference_free (priv->row_reference);
683 priv->row_reference = NULL;
686 if (priv->next_row_reference) {
687 gtk_tree_row_reference_free (priv->next_row_reference);
688 priv->next_row_reference = NULL;
692 g_free (priv->msg_uid);
693 priv->msg_uid = NULL;
696 G_OBJECT_CLASS(parent_class)->finalize (obj);
700 select_next_valid_row (GtkTreeModel *model,
701 GtkTreeRowReference **row_reference,
704 GtkTreeIter tmp_iter;
705 GtkTreePath *path, *next;
706 gboolean retval = FALSE;
708 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
710 path = gtk_tree_row_reference_get_path (*row_reference);
711 gtk_tree_model_get_iter (model, &tmp_iter, path);
712 gtk_tree_row_reference_free (*row_reference);
713 *row_reference = NULL;
715 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
716 next = gtk_tree_model_get_path (model, &tmp_iter);
717 *row_reference = gtk_tree_row_reference_new (model, next);
719 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
720 next = gtk_tree_model_get_path (model, &tmp_iter);
722 /* Ensure that we are not selecting the same */
723 if (gtk_tree_path_compare (path, next) != 0) {
724 *row_reference = gtk_tree_row_reference_new (model, next);
730 gtk_tree_path_free (path);
735 /* TODO: This should be in _init(), with the parameters as properties. */
737 modest_msg_view_window_construct (ModestMsgViewWindow *self,
738 const gchar *modest_account_name,
739 const gchar *msg_uid)
742 ModestMsgViewWindowPrivate *priv = NULL;
743 ModestWindowPrivate *parent_priv = NULL;
744 ModestDimmingRulesGroup *menu_rules_group = NULL;
745 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
746 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
748 obj = G_OBJECT (self);
749 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
750 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
752 priv->msg_uid = g_strdup (msg_uid);
755 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
756 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
757 gtk_widget_show (parent_priv->menubar);
758 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
760 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
761 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
762 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
764 /* Add common dimming rules */
765 modest_dimming_rules_group_add_rules (menu_rules_group,
766 modest_msg_view_menu_dimming_entries,
767 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
768 MODEST_WINDOW (self));
769 modest_dimming_rules_group_add_rules (toolbar_rules_group,
770 modest_msg_view_toolbar_dimming_entries,
771 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
772 MODEST_WINDOW (self));
773 modest_dimming_rules_group_add_rules (clipboard_rules_group,
774 modest_msg_view_clipboard_dimming_entries,
775 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
776 MODEST_WINDOW (self));
778 /* Insert dimming rules group for this window */
779 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
780 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
781 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
782 g_object_unref (menu_rules_group);
783 g_object_unref (toolbar_rules_group);
784 g_object_unref (clipboard_rules_group);
786 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
788 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
790 priv->clipboard_change_handler = g_signal_connect (G_OBJECT (gtk_clipboard_get (GDK_SELECTION_PRIMARY)), "owner-change", G_CALLBACK (modest_msg_view_window_clipboard_owner_change), obj);
791 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
792 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
793 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
794 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
795 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
796 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
797 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
798 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
799 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
800 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
802 g_signal_connect (G_OBJECT (obj), "key-release-event",
803 G_CALLBACK (modest_msg_view_window_key_event),
806 g_signal_connect (G_OBJECT (obj), "key-press-event",
807 G_CALLBACK (modest_msg_view_window_key_event),
810 g_signal_connect (G_OBJECT (obj), "window-state-event",
811 G_CALLBACK (modest_msg_view_window_window_state_event),
814 g_signal_connect (G_OBJECT (obj), "move-focus",
815 G_CALLBACK (on_move_focus), obj);
817 /* Mail Operation Queue */
818 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
820 G_CALLBACK (on_queue_changed),
823 /* Account manager */
824 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
826 G_CALLBACK(on_account_removed),
829 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
831 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
832 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
833 priv->last_search = NULL;
835 /* Init the clipboard actions dim status */
836 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
838 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
840 /* Check toolbar dimming rules */
841 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
842 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
846 /* FIXME: parameter checks */
848 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
849 const gchar *modest_account_name,
850 const gchar *msg_uid,
852 GtkTreeRowReference *row_reference)
854 ModestMsgViewWindow *window = NULL;
855 ModestMsgViewWindowPrivate *priv = NULL;
856 TnyFolder *header_folder = NULL;
857 ModestHeaderView *header_view = NULL;
858 ModestWindow *main_window = NULL;
859 ModestWindowMgr *mgr = NULL;
861 mgr = modest_runtime_get_window_mgr ();
862 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
863 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
865 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
867 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
869 /* Remember the message list's TreeModel so we can detect changes
870 * and change the list selection when necessary: */
872 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
874 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
875 MODEST_MAIN_WINDOW(main_window),
876 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
879 if (header_view != NULL){
880 header_folder = modest_header_view_get_folder(header_view);
881 priv->is_outbox = (modest_tny_folder_guess_folder_type (header_folder) == TNY_FOLDER_TYPE_OUTBOX);
882 g_assert(header_folder != NULL);
883 priv->header_folder_id = tny_folder_get_id(header_folder);
884 g_assert(priv->header_folder_id != NULL);
885 g_object_unref(header_folder);
888 priv->header_model = g_object_ref(model);
890 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
891 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
892 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
894 priv->row_reference = NULL;
895 priv->next_row_reference = NULL;
898 priv->row_changed_handler = g_signal_connect(
899 GTK_TREE_MODEL(model), "row-changed",
900 G_CALLBACK(modest_msg_view_window_on_row_changed),
902 priv->row_deleted_handler = g_signal_connect(
903 GTK_TREE_MODEL(model), "row-deleted",
904 G_CALLBACK(modest_msg_view_window_on_row_deleted),
906 priv->row_inserted_handler = g_signal_connect (
907 GTK_TREE_MODEL(model), "row-inserted",
908 G_CALLBACK(modest_msg_view_window_on_row_inserted),
910 priv->rows_reordered_handler = g_signal_connect(
911 GTK_TREE_MODEL(model), "rows-reordered",
912 G_CALLBACK(modest_msg_view_window_on_row_reordered),
915 if (header_view != NULL){
916 modest_header_view_add_observer(header_view,
917 MODEST_HEADER_VIEW_OBSERVER(window));
920 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
921 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
922 gtk_widget_show_all (GTK_WIDGET (window));
924 modest_msg_view_window_update_priority (window);
926 /* Check toolbar dimming rules */
927 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
929 return MODEST_WINDOW(window);
933 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
934 const gchar *modest_account_name,
935 const gchar *msg_uid)
937 ModestMsgViewWindow *window = NULL;
938 ModestMsgViewWindowPrivate *priv = NULL;
939 ModestWindowMgr *mgr = NULL;
941 mgr = modest_runtime_get_window_mgr ();
942 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
943 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
944 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
946 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
948 /* Remember that this is a search result,
949 * so we can disable some UI appropriately: */
950 priv->is_search_result = TRUE;
952 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
954 update_window_title (window);
955 modest_msg_view_window_update_priority (window);
957 return MODEST_WINDOW(window);
961 modest_msg_view_window_new_for_attachment (TnyMsg *msg,
962 const gchar *modest_account_name,
963 const gchar *msg_uid)
966 ModestMsgViewWindowPrivate *priv;
967 ModestWindowMgr *mgr = NULL;
969 g_return_val_if_fail (msg, NULL);
970 mgr = modest_runtime_get_window_mgr ();
971 obj = G_OBJECT (modest_window_mgr_get_msg_view_window (mgr));
972 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
973 modest_msg_view_window_construct (MODEST_MSG_VIEW_WINDOW (obj),
974 modest_account_name, msg_uid);
976 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
977 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
979 return MODEST_WINDOW(obj);
982 void modest_msg_view_window_on_row_changed(
983 GtkTreeModel *header_model,
986 ModestMsgViewWindow *window){
987 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
990 void modest_msg_view_window_on_row_deleted(
991 GtkTreeModel *header_model,
993 ModestMsgViewWindow *window){
994 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
997 /* On insertions we check if the folder still has the message we are
998 * showing or do not. If do not, we do nothing. Which means we are still
999 * not attached to any header folder and thus next/prev buttons are
1000 * still dimmed. Once the message that is shown by msg-view is found, the
1001 * new model of header-view will be attached and the references will be set.
1002 * On each further insertions dimming rules will be checked. However
1003 * this requires extra CPU time at least works.
1004 * (An message might be deleted from TnyFolder and thus will not be
1005 * inserted into the model again for example if it is removed by the
1006 * imap server and the header view is refreshed.)
1008 void modest_msg_view_window_on_row_inserted(
1009 GtkTreeModel *new_model,
1010 GtkTreePath *tree_path,
1011 GtkTreeIter *tree_iter,
1012 ModestMsgViewWindow *window){
1013 ModestMsgViewWindowPrivate *priv = NULL;
1014 TnyHeader *header = NULL;
1017 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1019 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1021 /* If we already has a model attached then the message shown by
1022 * msg-view is in it, and thus we do not need any actions but
1023 * to check the dimming rules.*/
1024 if(priv->header_model != NULL){
1025 if (priv->row_reference) {
1026 gtk_tree_row_reference_free(priv->next_row_reference);
1027 priv->next_row_reference = gtk_tree_row_reference_copy(
1028 priv->row_reference);
1029 select_next_valid_row (priv->header_model,
1030 &(priv->next_row_reference), FALSE);
1032 modest_ui_actions_check_toolbar_dimming_rules (
1033 MODEST_WINDOW (window));
1037 /* Check if the newly inserted message is the same we are actually
1038 * showing. IF not, we should remain detached from the header model
1039 * and thus prev and next toolbarbuttons should remain dimmed. */
1040 gtk_tree_model_get (new_model, tree_iter,
1041 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1042 uid = modest_tny_folder_get_header_unique_id(header);
1043 if(!g_str_equal(priv->msg_uid, uid)){
1045 g_object_unref(G_OBJECT(header));
1049 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1050 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1051 g_object_unref(G_OBJECT(header));
1055 /* Setup row_reference for the actual msg. */
1056 priv->row_reference = gtk_tree_row_reference_new(
1057 new_model, tree_path);
1058 if(priv->row_reference == NULL){
1059 g_warning("No reference for msg header item.");
1063 /* Attach new_model and connect some callback to it to become able
1064 * to detect changes in header-view. */
1065 priv->header_model = g_object_ref(new_model);
1066 g_signal_connect (new_model, "row-changed",
1067 G_CALLBACK (modest_msg_view_window_on_row_changed),
1069 g_signal_connect (new_model, "row-deleted",
1070 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1072 g_signal_connect (new_model, "rows-reordered",
1073 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1076 /* Now set up next_row_reference. */
1077 priv->next_row_reference = gtk_tree_row_reference_copy(
1078 priv->row_reference);
1079 select_next_valid_row (priv->header_model,
1080 &(priv->next_row_reference), FALSE);
1082 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1085 void modest_msg_view_window_on_row_reordered(
1086 GtkTreeModel *header_model,
1090 ModestMsgViewWindow *window){
1091 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1094 /* The modest_msg_view_window_update_model_replaced implements update
1095 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1096 * actually belongs to the header-view is the same as the TnyFolder of
1097 * the message of msg-view or not. If they are different, there is
1098 * nothing to do. If they are the same, then the model has replaced and
1099 * the reference in msg-view shall be replaced from the old model to
1100 * the new model. In this case the view will be detached from it's
1101 * header folder. From this point the next/prev buttons are dimmed.
1103 void modest_msg_view_window_update_model_replaced(
1104 ModestHeaderViewObserver *observer,
1105 GtkTreeModel *model,
1106 const gchar *tny_folder_id){
1107 ModestMsgViewWindowPrivate *priv = NULL;
1108 ModestMsgViewWindow *window = NULL;
1110 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1111 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1113 window = MODEST_MSG_VIEW_WINDOW(observer);
1114 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1116 /* If there is an other folder in the header-view then we do
1117 * not care about it's model (msg list). Else if the
1118 * header-view shows the folder the msg shown by us is in, we
1119 * shall replace our model reference and make some check. */
1120 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1123 /* Model is changed(replaced), so we should forget the old
1124 * one. Because there might be other references and there
1125 * might be some change on the model even if we unreferenced
1126 * it, we need to disconnect our signals here. */
1127 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1128 priv->row_changed_handler))
1129 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1130 priv->row_changed_handler);
1131 priv->row_changed_handler = 0;
1132 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1133 priv->row_deleted_handler))
1134 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1135 priv->row_deleted_handler);
1136 priv->row_deleted_handler = 0;
1137 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1138 priv->row_inserted_handler))
1139 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1140 priv->row_inserted_handler);
1141 priv->row_inserted_handler = 0;
1142 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1143 priv->rows_reordered_handler))
1144 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1145 priv->rows_reordered_handler);
1146 priv->rows_reordered_handler = 0;
1147 g_object_unref(priv->header_model);
1148 priv->header_model = NULL;
1149 if (priv->row_reference)
1150 g_object_unref(priv->row_reference);
1151 priv->row_reference = NULL;
1152 if (priv->next_row_reference)
1153 g_object_unref(priv->next_row_reference);
1154 priv->next_row_reference = NULL;
1156 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1158 g_assert(model != NULL);
1160 /* Also we must connect to the new model for row insertions.
1161 * Only for insertions now. We will need other ones only after
1162 * the msg is show by msg-view is added to the new model. */
1163 priv->row_inserted_handler = g_signal_connect (
1164 model, "row-inserted",
1165 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1170 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1172 ModestMsgViewWindowPrivate *priv= NULL;
1174 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1175 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1177 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1181 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1183 ModestMsgViewWindowPrivate *priv= NULL;
1185 TnyHeader *header = NULL;
1186 GtkTreePath *path = NULL;
1189 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1190 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1192 /* If the message was not obtained from a treemodel,
1193 * for instance if it was opened directly by the search UI:
1195 if (priv->header_model == NULL || priv->row_reference == NULL) {
1196 msg = modest_msg_view_window_get_message (self);
1198 header = tny_msg_get_header (msg);
1199 g_object_unref (msg);
1204 /* Get iter of the currently selected message in the header view: */
1205 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1206 * instead of sometimes retrieving it from the header view?
1207 * Then we wouldn't be dependent on the message actually still being selected
1208 * in the header view. murrayc. */
1209 if (!gtk_tree_row_reference_valid (priv->row_reference))
1211 path = gtk_tree_row_reference_get_path (priv->row_reference);
1212 g_return_val_if_fail (path != NULL, NULL);
1213 gtk_tree_model_get_iter (priv->header_model,
1217 /* Get current message header */
1218 gtk_tree_model_get (priv->header_model, &iter,
1219 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1222 gtk_tree_path_free (path);
1227 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1229 ModestMsgViewWindowPrivate *priv;
1231 g_return_val_if_fail (self, NULL);
1233 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1235 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1239 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1241 ModestMsgViewWindowPrivate *priv;
1243 g_return_val_if_fail (self, NULL);
1245 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1247 return (const gchar*) priv->msg_uid;
1251 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1254 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1255 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1256 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1260 is_active = gtk_toggle_action_get_active (toggle);
1263 gtk_widget_show (priv->find_toolbar);
1264 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1266 gtk_widget_hide (priv->find_toolbar);
1269 /* update the toggle buttons status */
1270 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1271 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1272 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1273 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1278 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1279 ModestMsgViewWindow *obj)
1281 GtkToggleAction *toggle;
1282 ModestWindowPrivate *parent_priv;
1283 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1285 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1286 gtk_toggle_action_set_active (toggle, FALSE);
1290 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1291 ModestMsgViewWindow *obj)
1293 gchar *current_search;
1294 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1296 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1297 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1301 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1303 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1304 g_free (current_search);
1305 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1309 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1311 g_free (priv->last_search);
1312 priv->last_search = g_strdup (current_search);
1313 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1316 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1317 g_free (priv->last_search);
1318 priv->last_search = NULL;
1320 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1323 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1324 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1325 g_free (priv->last_search);
1326 priv->last_search = NULL;
1328 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1332 g_free (current_search);
1337 modest_msg_view_window_set_zoom (ModestWindow *window,
1340 ModestMsgViewWindowPrivate *priv;
1341 ModestWindowPrivate *parent_priv;
1342 GtkAction *action = NULL;
1343 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1345 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1347 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1348 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1349 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1351 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1352 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1354 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1358 modest_msg_view_window_get_zoom (ModestWindow *window)
1360 ModestMsgViewWindowPrivate *priv;
1362 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1364 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1365 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1369 modest_msg_view_window_zoom_plus (ModestWindow *window)
1371 ModestWindowPrivate *parent_priv;
1372 GtkRadioAction *zoom_radio_action;
1373 GSList *group, *node;
1375 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1376 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1377 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1379 group = gtk_radio_action_get_group (zoom_radio_action);
1381 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1382 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1386 for (node = group; node != NULL; node = g_slist_next (node)) {
1387 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1388 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1396 modest_msg_view_window_zoom_minus (ModestWindow *window)
1398 ModestWindowPrivate *parent_priv;
1399 GtkRadioAction *zoom_radio_action;
1400 GSList *group, *node;
1402 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1403 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1404 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1406 group = gtk_radio_action_get_group (zoom_radio_action);
1408 for (node = group; node != NULL; node = g_slist_next (node)) {
1409 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1410 if (node->next != NULL) {
1411 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1414 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1424 modest_msg_view_window_key_event (GtkWidget *window,
1429 if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up ||
1430 event->keyval == GDK_Down || event->keyval == GDK_KP_Down ||
1431 event->keyval == GDK_Page_Up || event->keyval == GDK_KP_Page_Up ||
1432 event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down ||
1433 event->keyval == GDK_Home || event->keyval == GDK_KP_Home ||
1434 event->keyval == GDK_End || event->keyval == GDK_KP_End) {
1435 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1436 gboolean return_value;
1438 if (event->type == GDK_KEY_RELEASE) {
1439 GtkScrollType scroll_type;
1441 switch (event->keyval) {
1444 scroll_type = GTK_SCROLL_STEP_UP; break;
1447 scroll_type = GTK_SCROLL_STEP_DOWN; break;
1449 case GDK_KP_Page_Up:
1450 scroll_type = GTK_SCROLL_PAGE_UP; break;
1452 case GDK_KP_Page_Down:
1453 scroll_type = GTK_SCROLL_PAGE_DOWN; break;
1456 scroll_type = GTK_SCROLL_START; break;
1459 scroll_type = GTK_SCROLL_END; break;
1460 default: scroll_type = GTK_SCROLL_NONE;
1463 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child",
1464 scroll_type, FALSE, &return_value);
1475 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1478 ModestMsgViewWindowPrivate *priv;
1479 GtkTreeIter tmp_iter;
1480 gboolean is_last_selected;
1482 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1483 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1485 /*if no model (so no rows at all), then virtually we are the last*/
1486 if (!priv->header_model || !priv->row_reference)
1489 path = gtk_tree_row_reference_get_path (priv->row_reference);
1493 is_last_selected = TRUE;
1494 while (is_last_selected) {
1496 gtk_tree_path_next (path);
1497 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1499 gtk_tree_model_get (priv->header_model, &tmp_iter,
1500 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1503 if (msg_is_visible (header, priv->is_outbox))
1504 is_last_selected = FALSE;
1505 g_object_unref(G_OBJECT(header));
1508 gtk_tree_path_free (path);
1509 return is_last_selected;
1513 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1515 ModestMsgViewWindowPrivate *priv;
1517 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1518 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1520 return priv->header_model != NULL;
1524 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1526 ModestMsgViewWindowPrivate *priv;
1528 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1529 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1531 return priv->is_search_result;
1535 msg_is_visible (TnyHeader *header, gboolean check_outbox)
1537 return (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) &&
1538 ( (!check_outbox) || (modest_tny_all_send_queues_get_msg_status (header) != MODEST_TNY_SEND_QUEUE_FAILED)) ;
1543 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1546 ModestMsgViewWindowPrivate *priv;
1547 gboolean is_first_selected;
1548 GtkTreeIter tmp_iter;
1549 /* gchar * path_string;*/
1551 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1552 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1554 /*if no model (so no rows at all), then virtually we are the first*/
1555 if (!priv->header_model || !priv->row_reference)
1558 path = gtk_tree_row_reference_get_path (priv->row_reference);
1562 /* path_string = gtk_tree_path_to_string (path);
1563 is_first_selected = strcmp (path_string, "0");
1565 g_free (path_string);
1566 gtk_tree_path_free (path);
1568 return is_first_selected;*/
1570 is_first_selected = TRUE;
1571 while (is_first_selected) {
1573 if(!gtk_tree_path_prev (path))
1575 /* Here the 'if' is needless for logic, but let make sure
1576 * iter is valid for gtk_tree_model_get. */
1577 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1579 gtk_tree_model_get (priv->header_model, &tmp_iter,
1580 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1583 if (msg_is_visible (header, priv->is_outbox))
1584 is_first_selected = FALSE;
1585 g_object_unref(G_OBJECT(header));
1588 gtk_tree_path_free (path);
1589 return is_first_selected;
1593 * Reads the message whose summary item is @header. It takes care of
1594 * several things, among others:
1596 * If the message was not previously downloaded then ask the user
1597 * before downloading. If there is no connection launch the connection
1598 * dialog. Update toolbar dimming rules.
1600 * Returns: TRUE if the mail operation was started, otherwise if the
1601 * user do not want to download the message, or if the user do not
1602 * want to connect, then the operation is not issued
1605 message_reader (ModestMsgViewWindow *window,
1606 ModestMsgViewWindowPrivate *priv,
1608 GtkTreeRowReference *row_reference)
1610 ModestMailOperation *mail_op = NULL;
1611 gboolean already_showing = FALSE;
1612 ModestWindow *msg_window = NULL;
1613 ModestWindowMgr *mgr;
1615 g_return_val_if_fail (row_reference != NULL, FALSE);
1617 mgr = modest_runtime_get_window_mgr ();
1618 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1619 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1622 gtk_window_present (GTK_WINDOW (msg_window));
1623 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1627 /* Msg download completed */
1628 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED)) {
1629 /* Ask the user if he wants to download the message if
1631 if (!tny_device_is_online (modest_runtime_get_device())) {
1632 TnyFolder *folder = NULL;
1633 GtkResponseType response;
1635 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1636 _("mcen_nc_get_msg"));
1637 if (response == GTK_RESPONSE_CANCEL)
1640 /* Offer the connection dialog if necessary */
1641 folder = tny_header_get_folder (header);
1643 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1644 TNY_FOLDER_STORE (folder))) {
1645 g_object_unref (folder);
1648 g_object_unref (folder);
1653 /* New mail operation */
1654 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1655 modest_ui_actions_get_msgs_full_error_handler,
1658 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1659 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1660 g_object_unref (mail_op);
1662 /* Update toolbar dimming rules */
1663 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1669 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1671 ModestMsgViewWindowPrivate *priv;
1672 GtkTreePath *path= NULL;
1673 GtkTreeIter tmp_iter;
1675 gboolean retval = TRUE;
1676 GtkTreeRowReference *row_reference = NULL;
1678 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1679 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1681 if (!priv->row_reference)
1684 /* Update the next row reference if it's not valid. This could
1685 happen if for example the header which it was pointing to,
1686 was deleted. The best place to do it is in the row-deleted
1687 handler but the tinymail model do not work like the glib
1688 tree models and reports the deletion when the row is still
1690 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1691 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1692 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1693 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1696 if (priv->next_row_reference)
1697 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1701 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1703 gtk_tree_model_get_iter (priv->header_model,
1706 gtk_tree_path_free (path);
1708 gtk_tree_model_get (priv->header_model, &tmp_iter,
1709 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1712 /* Read the message & show it */
1713 if (!message_reader (window, priv, header, row_reference)) {
1715 gtk_tree_row_reference_free (row_reference);
1719 g_object_unref (header);
1725 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1727 ModestMsgViewWindowPrivate *priv = NULL;
1728 TnyHeader *header = NULL;
1730 GtkTreePath *path = NULL;
1731 GtkTreeRowReference *row_reference = NULL;
1733 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1734 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1736 /* Check that the model is not empty */
1737 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1740 /* Get the header */
1741 gtk_tree_model_get (priv->header_model,
1743 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1745 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1746 if (!msg_is_visible (header, priv->is_outbox)) {
1747 g_object_unref (header);
1748 return modest_msg_view_window_select_next_message (self);
1751 path = gtk_tree_model_get_path (priv->header_model, &iter);
1752 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1753 gtk_tree_path_free (path);
1755 /* Read the message & show it */
1756 message_reader (self, priv, header, row_reference);
1759 g_object_unref (header);
1765 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1767 ModestMsgViewWindowPrivate *priv = NULL;
1769 GtkTreeRowReference *row_reference = NULL;
1771 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1772 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1774 /* Return inmediatly if there is no header model */
1775 if (!priv->header_model || !priv->row_reference)
1778 path = gtk_tree_row_reference_get_path (priv->row_reference);
1779 while (gtk_tree_path_prev (path)) {
1783 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1784 gtk_tree_model_get (priv->header_model, &iter,
1785 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1789 if (!msg_is_visible (header, priv->is_outbox)) {
1790 g_object_unref (header);
1794 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1795 /* Read the message & show it */
1796 if (!message_reader (window, priv, header, row_reference)) {
1797 gtk_tree_row_reference_free (row_reference);
1798 g_object_unref (header);
1802 gtk_tree_path_free (path);
1803 g_object_unref (header);
1808 gtk_tree_path_free (path);
1813 view_msg_cb (ModestMailOperation *mail_op,
1820 ModestMsgViewWindow *self = NULL;
1821 ModestMsgViewWindowPrivate *priv = NULL;
1822 GtkTreeRowReference *row_reference = NULL;
1824 /* If there was any error */
1825 row_reference = (GtkTreeRowReference *) user_data;
1826 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1827 gtk_tree_row_reference_free (row_reference);
1831 /* Get the window */
1832 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1833 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1834 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1836 /* Update the row reference */
1837 gtk_tree_row_reference_free (priv->row_reference);
1838 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1839 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1840 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1841 gtk_tree_row_reference_free (row_reference);
1843 /* Mark header as read */
1844 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1845 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1847 /* Set new message */
1848 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1849 modest_msg_view_window_update_priority (self);
1850 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1851 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1853 /* Set the new message uid of the window */
1854 if (priv->msg_uid) {
1855 g_free (priv->msg_uid);
1856 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1859 /* Notify the observers */
1860 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1861 0, priv->header_model, priv->row_reference);
1863 /* Free new references */
1864 g_object_unref (self);
1868 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1870 ModestMsgViewWindowPrivate *priv;
1872 TnyFolderType folder_type;
1874 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1876 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1878 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1882 folder = tny_msg_get_folder (msg);
1884 folder_type = tny_folder_get_folder_type (folder);
1885 g_object_unref (folder);
1887 g_object_unref (msg);
1895 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1897 ModestMsgViewWindowPrivate *priv;
1898 TnyHeader *header = NULL;
1899 TnyHeaderFlags flags = 0;
1901 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1903 if (priv->header_model && priv->row_reference) {
1905 GtkTreePath *path = NULL;
1907 path = gtk_tree_row_reference_get_path (priv->row_reference);
1908 g_return_if_fail (path != NULL);
1909 gtk_tree_model_get_iter (priv->header_model,
1911 gtk_tree_row_reference_get_path (priv->row_reference));
1913 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1915 gtk_tree_path_free (path);
1918 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1920 header = tny_msg_get_header (msg);
1921 g_object_unref (msg);
1926 flags = tny_header_get_flags (header);
1927 g_object_unref(G_OBJECT(header));
1930 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1935 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1937 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1938 ModestWindowPrivate *parent_priv;
1939 ModestWindowMgr *mgr;
1940 gboolean is_fullscreen;
1941 GtkAction *fs_toggle_action;
1944 mgr = modest_runtime_get_window_mgr ();
1945 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1947 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1949 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1950 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1951 if (is_fullscreen != active) {
1952 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1961 set_homogeneous (GtkWidget *widget,
1964 if (GTK_IS_TOOL_ITEM (widget)) {
1965 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1966 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1971 modest_msg_view_window_show_toolbar (ModestWindow *self,
1972 gboolean show_toolbar)
1974 ModestMsgViewWindowPrivate *priv = NULL;
1975 ModestWindowPrivate *parent_priv;
1976 GtkWidget *reply_button = NULL, *menu = NULL;
1977 GtkWidget *placeholder = NULL;
1979 const gchar *action_name;
1982 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1983 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1985 /* Set optimized view status */
1986 priv->optimized_view = !show_toolbar;
1988 if (!parent_priv->toolbar) {
1989 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1991 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1993 /* Set homogeneous toolbar */
1994 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1995 set_homogeneous, NULL);
1997 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1998 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1999 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
2000 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
2001 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2002 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2003 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
2004 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
2006 /* Add ProgressBar (Transfer toolbar) */
2007 priv->progress_bar = modest_progress_bar_widget_new ();
2008 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
2009 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
2010 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
2011 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
2012 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
2014 /* Connect cancel 'clicked' signal to abort progress mode */
2015 g_signal_connect(priv->cancel_toolitem, "clicked",
2016 G_CALLBACK(cancel_progressbar),
2019 /* Add it to the observers list */
2020 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
2023 hildon_window_add_toolbar (HILDON_WINDOW (self),
2024 GTK_TOOLBAR (parent_priv->toolbar));
2026 /* Set reply button tap and hold menu */
2027 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2028 "/ToolBar/ToolbarMessageReply");
2029 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
2030 "/ToolbarReplyCSM");
2031 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
2035 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
2036 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
2037 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
2039 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2040 if (modest_msg_view_window_transfer_mode_enabled (MODEST_MSG_VIEW_WINDOW (self)))
2041 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_TRANSFER);
2043 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW (self), TOOLBAR_MODE_NORMAL);
2046 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2047 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2050 /* Update also the actions (to update the toggles in the
2051 menus), we have to do it manually because some other window
2052 of the same time could have changed it (remember that the
2053 toolbar fullscreen mode is shared by all the windows of the
2055 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2056 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2058 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2060 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2061 modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2066 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2068 ModestMsgViewWindow *window)
2070 if (!GTK_WIDGET_VISIBLE (window))
2073 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2077 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2079 ModestMsgViewWindowPrivate *priv;
2081 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2082 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2084 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2088 cancel_progressbar (GtkToolButton *toolbutton,
2089 ModestMsgViewWindow *self)
2092 ModestMsgViewWindowPrivate *priv;
2094 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2096 /* Get operation observers and cancel its current operation */
2097 tmp = priv->progress_widgets;
2099 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2100 tmp=g_slist_next(tmp);
2104 observers_empty (ModestMsgViewWindow *self)
2107 ModestMsgViewWindowPrivate *priv;
2108 gboolean is_empty = TRUE;
2109 guint pending_ops = 0;
2111 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2112 tmp = priv->progress_widgets;
2114 /* Check all observers */
2115 while (tmp && is_empty) {
2116 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2117 is_empty = pending_ops == 0;
2119 tmp = g_slist_next(tmp);
2126 on_account_removed (TnyAccountStore *account_store,
2127 TnyAccount *account,
2130 /* Do nothing if it's a transport account, because we only
2131 show the messages of a store account */
2132 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2133 const gchar *parent_acc = NULL;
2134 const gchar *our_acc = NULL;
2136 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2137 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2139 /* Close this window if I'm showing a message of the removed account */
2140 if (strcmp (parent_acc, our_acc) == 0)
2141 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2146 on_mail_operation_started (ModestMailOperation *mail_op,
2149 ModestMsgViewWindow *self;
2150 ModestMailOperationTypeOperation op_type;
2152 ModestMsgViewWindowPrivate *priv;
2154 self = MODEST_MSG_VIEW_WINDOW (user_data);
2155 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2156 op_type = modest_mail_operation_get_type_operation (mail_op);
2157 tmp = priv->progress_widgets;
2159 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2160 set_toolbar_transfer_mode(self);
2162 modest_progress_object_add_operation (
2163 MODEST_PROGRESS_OBJECT (tmp->data),
2165 tmp = g_slist_next (tmp);
2171 on_mail_operation_finished (ModestMailOperation *mail_op,
2174 ModestMsgViewWindow *self;
2175 ModestMailOperationTypeOperation op_type;
2177 ModestMsgViewWindowPrivate *priv;
2179 self = MODEST_MSG_VIEW_WINDOW (user_data);
2180 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2181 op_type = modest_mail_operation_get_type_operation (mail_op);
2182 tmp = priv->progress_widgets;
2184 if (op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE || op_type == MODEST_MAIL_OPERATION_TYPE_OPEN ) {
2186 modest_progress_object_remove_operation (
2187 MODEST_PROGRESS_OBJECT (tmp->data),
2189 tmp = g_slist_next (tmp);
2192 /* If no more operations are being observed, NORMAL mode is enabled again */
2193 if (observers_empty (self)) {
2194 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2200 on_queue_changed (ModestMailOperationQueue *queue,
2201 ModestMailOperation *mail_op,
2202 ModestMailOperationQueueNotification type,
2203 ModestMsgViewWindow *self)
2205 ModestMsgViewWindowPrivate *priv;
2207 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
2209 /* If this operations was created by another window, do nothing */
2210 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2213 if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2214 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2216 "operation-started",
2217 G_CALLBACK (on_mail_operation_started),
2219 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2221 "operation-finished",
2222 G_CALLBACK (on_mail_operation_finished),
2224 } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2225 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2227 "operation-started");
2228 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2230 "operation-finished");
2235 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2237 ModestMsgViewWindowPrivate *priv;
2238 GList *selected_attachments = NULL;
2240 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2241 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2243 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2245 return selected_attachments;
2249 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2251 ModestMsgViewWindowPrivate *priv;
2252 const gchar *msg_uid;
2253 gchar *attachment_uid = NULL;
2254 gint attachment_index = 0;
2257 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2258 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2259 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2261 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2262 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2263 attachment_index = g_list_index (attachments, mime_part);
2264 g_list_free (attachments);
2266 if (msg_uid && attachment_index >= 0) {
2267 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2270 if (mime_part == NULL) {
2271 gboolean error = FALSE;
2272 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2273 if (selected_attachments == NULL) {
2275 } else if (g_list_length (selected_attachments) > 1) {
2276 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2279 mime_part = (TnyMimePart *) selected_attachments->data;
2280 g_object_ref (mime_part);
2282 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2283 g_list_free (selected_attachments);
2288 g_object_ref (mime_part);
2291 if (tny_mime_part_is_purged (mime_part)) {
2292 g_object_unref (mime_part);
2296 if (!TNY_IS_MSG (mime_part)) {
2297 gchar *filepath = NULL;
2298 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2299 const gchar *content_type;
2300 TnyFsStream *temp_stream = NULL;
2301 temp_stream = modest_utils_create_temp_stream (att_filename, attachment_uid,
2304 if (temp_stream != NULL) {
2305 content_type = tny_mime_part_get_content_type (mime_part);
2306 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2308 /* make the file read-only */
2309 if (g_chmod(filepath, 0444) != 0)
2310 g_warning ("%s: failed to set file '%s' to read-only: %s",
2311 __FUNCTION__, filepath, strerror(errno));
2313 modest_platform_activate_file (filepath, content_type);
2314 g_object_unref (temp_stream);
2316 /* NOTE: files in the temporary area will be automatically
2317 * cleaned after some time if they are no longer in use */
2318 } else if (filepath != NULL) {
2319 /* the file may already exist but it isn't writable,
2320 * let's try to open it anyway */
2321 content_type = tny_mime_part_get_content_type (mime_part);
2322 modest_platform_activate_file (filepath, content_type);
2326 /* message attachment */
2327 TnyHeader *header = NULL;
2328 ModestWindowMgr *mgr;
2329 ModestWindow *msg_win = NULL;
2332 header = tny_msg_get_header (TNY_MSG (mime_part));
2333 mgr = modest_runtime_get_window_mgr ();
2334 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2337 if (msg_win) /* there is already a window for this uid; top it */
2338 gtk_window_present (GTK_WINDOW(msg_win));
2340 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2341 * thus, we don't do anything */
2342 g_warning ("window for is already being created");
2344 /* it's not found, so create a new window for it */
2345 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2346 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2348 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2349 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2350 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2351 modest_window_get_zoom (MODEST_WINDOW (window)));
2352 modest_window_mgr_register_window (mgr, msg_win);
2353 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2354 gtk_widget_show_all (GTK_WIDGET (msg_win));
2357 g_object_unref (mime_part);
2373 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2374 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2375 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2376 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2379 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2383 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2384 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2385 g_free (pair->filename);
2386 g_object_unref (pair->part);
2387 g_slice_free (SaveMimePartPair, pair);
2389 g_list_free (info->pairs);
2392 gtk_widget_destroy (info->banner);
2393 g_object_unref (info->banner);
2394 g_slice_free (SaveMimePartInfo, info);
2399 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2401 if (info->pairs != NULL) {
2402 save_mime_part_to_file (info);
2405 result = info->result;
2407 /* This is a GDK lock because we are an idle callback and
2408 * hildon_banner_show_information is or does Gtk+ code */
2410 gdk_threads_enter (); /* CHECKED */
2411 save_mime_part_info_free (info, TRUE);
2413 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2415 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2417 gdk_threads_leave (); /* CHECKED */
2424 save_mime_part_to_file (SaveMimePartInfo *info)
2426 GnomeVFSResult result;
2427 GnomeVFSHandle *handle;
2429 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2431 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0644);
2432 if (result == GNOME_VFS_OK) {
2433 stream = tny_vfs_stream_new (handle);
2434 tny_mime_part_decode_to_stream (pair->part, stream);
2435 g_object_unref (G_OBJECT (stream));
2436 g_object_unref (pair->part);
2437 g_slice_free (SaveMimePartPair, pair);
2438 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2439 info->result = TRUE;
2441 save_mime_part_info_free (info, FALSE);
2442 info->result = FALSE;
2445 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2450 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2452 gboolean is_ok = TRUE;
2453 gint replaced_files = 0;
2454 const GList *files = info->pairs;
2457 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2458 SaveMimePartPair *pair = iter->data;
2459 if (modest_utils_file_exists (pair->filename)) {
2463 if (replaced_files) {
2464 GtkWidget *confirm_overwrite_dialog;
2465 const gchar *message = (replaced_files == 1) ?
2466 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2467 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2468 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2471 gtk_widget_destroy (confirm_overwrite_dialog);
2475 save_mime_part_info_free (info, TRUE);
2477 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2478 _CS("sfil_ib_saving"));
2479 info->banner = g_object_ref (banner);
2480 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2481 g_object_unref (banner);
2488 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2490 gboolean clean_list = FALSE;
2491 ModestMsgViewWindowPrivate *priv;
2492 GList *files_to_save = NULL;
2493 GtkWidget *save_dialog = NULL;
2494 gchar *folder = NULL;
2495 gboolean canceled = FALSE;
2496 const gchar *filename = NULL;
2497 gchar *save_multiple_str = NULL;
2499 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2500 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2502 if (mime_parts == NULL) {
2503 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2504 if (mime_parts == NULL)
2509 /* prepare dialog */
2510 if (mime_parts->next == NULL) {
2511 /* only one attachment selected */
2512 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2513 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2514 filename = tny_mime_part_get_filename (mime_part);
2516 g_warning ("Tried to save a non-file attachment");
2520 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2521 g_list_length (mime_parts));
2524 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2525 GTK_FILE_CHOOSER_ACTION_SAVE);
2528 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2529 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2533 if (filename != NULL)
2534 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2537 /* if multiple, set multiple string */
2538 if (save_multiple_str) {
2539 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2543 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2544 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2546 if (!modest_utils_folder_writable (chooser_uri)) {
2547 hildon_banner_show_information
2548 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2552 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2553 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2555 if (tny_mime_part_is_attachment (mime_part)) {
2556 SaveMimePartPair *pair;
2558 if ((mime_parts->next != NULL) &&
2559 (tny_mime_part_get_filename (mime_part) == NULL))
2562 pair = g_slice_new0 (SaveMimePartPair);
2563 if (mime_parts->next == NULL) {
2564 pair->filename = g_strdup (chooser_uri);
2567 g_build_filename (chooser_uri,
2568 tny_mime_part_get_filename (mime_part), NULL);
2570 pair->part = g_object_ref (mime_part);
2571 files_to_save = g_list_prepend (files_to_save, pair);
2575 g_free (chooser_uri);
2578 gtk_widget_destroy (save_dialog);
2581 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2582 g_list_free (mime_parts);
2585 if (files_to_save != NULL) {
2586 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2587 info->pairs = files_to_save;
2588 info->result = TRUE;
2589 save_mime_parts_to_file_with_checks (info);
2594 show_remove_attachment_information (gpointer userdata)
2596 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2597 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2599 /* We're outside the main lock */
2600 gdk_threads_enter ();
2602 if (priv->remove_attachment_banner != NULL) {
2603 gtk_widget_destroy (priv->remove_attachment_banner);
2604 g_object_unref (priv->remove_attachment_banner);
2607 priv->remove_attachment_banner = g_object_ref (
2608 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2610 gdk_threads_leave ();
2616 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2618 ModestMsgViewWindowPrivate *priv;
2619 GList *mime_parts = NULL, *node;
2620 gchar *confirmation_message;
2624 /* TnyFolder *folder; */
2626 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2627 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2630 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2632 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2634 /* Remove already purged messages from mime parts list */
2636 while (node != NULL) {
2637 TnyMimePart *part = TNY_MIME_PART (node->data);
2638 if (tny_mime_part_is_purged (part)) {
2639 GList *deleted_node = node;
2640 node = g_list_next (node);
2641 g_object_unref (part);
2642 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2644 node = g_list_next (node);
2648 if (mime_parts == NULL)
2651 n_attachments = g_list_length (mime_parts);
2652 if (n_attachments == 1) {
2653 const gchar *filename;
2655 if (TNY_IS_MSG (mime_parts->data)) {
2657 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2658 filename = tny_header_get_subject (header);
2659 g_object_unref (header);
2660 if (filename == NULL)
2661 filename = _("mail_va_no_subject");
2663 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2665 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2667 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2668 "mcen_nc_purge_files_text",
2669 n_attachments), n_attachments);
2671 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2672 confirmation_message);
2673 g_free (confirmation_message);
2675 if (response != GTK_RESPONSE_OK)
2678 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2679 /* folder = tny_msg_get_folder (msg); */
2680 /* tny_msg_uncache_attachments (msg); */
2681 /* tny_folder_refresh (folder, NULL); */
2682 /* g_object_unref (folder); */
2684 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2685 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2686 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2689 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2690 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2691 tny_msg_rewrite_cache (msg);
2692 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2694 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2695 g_list_free (mime_parts);
2697 if (priv->purge_timeout > 0) {
2698 g_source_remove (priv->purge_timeout);
2699 priv->purge_timeout = 0;
2702 if (priv->remove_attachment_banner) {
2703 gtk_widget_destroy (priv->remove_attachment_banner);
2704 g_object_unref (priv->remove_attachment_banner);
2705 priv->remove_attachment_banner = NULL;
2713 update_window_title (ModestMsgViewWindow *window)
2715 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2717 TnyHeader *header = NULL;
2718 const gchar *subject = NULL;
2720 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2723 header = tny_msg_get_header (msg);
2724 subject = tny_header_get_subject (header);
2725 g_object_unref (msg);
2728 if ((subject == NULL)||(subject[0] == '\0'))
2729 subject = _("mail_va_no_subject");
2731 gtk_window_set_title (GTK_WINDOW (window), subject);
2735 static void on_move_focus (GtkWidget *widget,
2736 GtkDirectionType direction,
2739 g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus");