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-maemo-utils.h>
39 #include <modest-tny-msg.h>
40 #include <modest-msg-view-window.h>
41 #include <modest-attachments-view.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-widget.h"
51 #include "modest-defs.h"
52 #include "modest-hildon-includes.h"
53 #include "modest-ui-dimming-manager.h"
54 #include <gdk/gdkkeysyms.h>
55 #include <modest-tny-account.h>
56 #include <modest-mime-part-view.h>
57 #include <modest-isearch-view.h>
60 #define DEFAULT_FOLDER "MyDocs/.documents"
62 static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass);
63 static void modest_msg_view_window_init (ModestMsgViewWindow *obj);
64 static void modest_header_view_observer_init(
65 ModestHeaderViewObserverIface *iface_class);
66 static void modest_msg_view_window_finalize (GObject *obj);
67 static void modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *obj,
69 static void modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
70 ModestMsgViewWindow *obj);
71 static void modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
72 ModestMsgViewWindow *obj);
74 static void modest_msg_view_window_disconnect_signals (ModestWindow *self);
75 static void modest_msg_view_window_set_zoom (ModestWindow *window,
77 static gdouble modest_msg_view_window_get_zoom (ModestWindow *window);
78 static gboolean modest_msg_view_window_zoom_minus (ModestWindow *window);
79 static gboolean modest_msg_view_window_zoom_plus (ModestWindow *window);
80 static gboolean modest_msg_view_window_key_release_event (GtkWidget *window,
83 static gboolean modest_msg_view_window_window_state_event (GtkWidget *widget,
84 GdkEventWindowState *event,
86 static void modest_msg_view_window_scroll_up (ModestWindow *window);
87 static void modest_msg_view_window_scroll_down (ModestWindow *window);
88 static void modest_msg_view_window_update_priority (ModestMsgViewWindow *window);
90 static void modest_msg_view_window_show_toolbar (ModestWindow *window,
91 gboolean show_toolbar);
93 static void modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
95 ModestMsgViewWindow *window);
96 void modest_msg_view_window_on_row_changed(
97 GtkTreeModel *header_model,
100 ModestMsgViewWindow *window);
102 void modest_msg_view_window_on_row_deleted(
103 GtkTreeModel *header_model,
105 ModestMsgViewWindow *window);
107 void modest_msg_view_window_on_row_inserted(
108 GtkTreeModel *header_model,
109 GtkTreePath *tree_path,
110 GtkTreeIter *tree_iter,
111 ModestMsgViewWindow *window);
113 void modest_msg_view_window_on_row_reordered(
114 GtkTreeModel *header_model,
118 ModestMsgViewWindow *window);
120 void modest_msg_view_window_update_model_replaced(
121 ModestHeaderViewObserver *window,
123 const gchar *tny_folder_id);
125 static void cancel_progressbar (GtkToolButton *toolbutton,
126 ModestMsgViewWindow *self);
128 static void on_queue_changed (ModestMailOperationQueue *queue,
129 ModestMailOperation *mail_op,
130 ModestMailOperationQueueNotification type,
131 ModestMsgViewWindow *self);
133 static void on_account_removed (TnyAccountStore *account_store,
137 static void on_move_focus (ModestMsgViewWindow *window,
138 GtkDirectionType direction,
141 static void view_msg_cb (ModestMailOperation *mail_op,
148 static void set_toolbar_mode (ModestMsgViewWindow *self,
149 ModestToolBarModes mode);
151 static void update_window_title (ModestMsgViewWindow *window);
153 static gboolean set_toolbar_transfer_mode (ModestMsgViewWindow *self);
154 static void init_window (ModestMsgViewWindow *obj);
157 /* list my signals */
163 static const GtkToggleActionEntry msg_view_toggle_action_entries [] = {
164 { "FindInMessage", MODEST_TOOLBAR_ICON_FIND, N_("qgn_toolb_gene_find"), NULL, NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
165 { "ToolsFindInMessage", NULL, N_("mcen_me_viewer_find"), "<CTRL>F", NULL, G_CALLBACK (modest_msg_view_window_toggle_find_toolbar), FALSE },
168 static const GtkRadioActionEntry msg_view_zoom_action_entries [] = {
169 { "Zoom50", NULL, N_("mcen_me_viewer_50"), NULL, NULL, 50 },
170 { "Zoom80", NULL, N_("mcen_me_viewer_80"), NULL, NULL, 80 },
171 { "Zoom100", NULL, N_("mcen_me_viewer_100"), NULL, NULL, 100 },
172 { "Zoom120", NULL, N_("mcen_me_viewer_120"), NULL, NULL, 120 },
173 { "Zoom150", NULL, N_("mcen_me_viewer_150"), NULL, NULL, 150 },
174 { "Zoom200", NULL, N_("mcen_me_viewer_200"), NULL, NULL, 200 }
177 typedef struct _ModestMsgViewWindowPrivate ModestMsgViewWindowPrivate;
178 struct _ModestMsgViewWindowPrivate {
181 GtkWidget *main_scroll;
182 GtkWidget *find_toolbar;
185 /* Progress observers */
186 GtkWidget *progress_bar;
187 GSList *progress_widgets;
190 GtkWidget *progress_toolitem;
191 GtkWidget *cancel_toolitem;
192 GtkWidget *prev_toolitem;
193 GtkWidget *next_toolitem;
194 ModestToolBarModes current_toolbar_mode;
196 /* Optimized view enabled */
197 gboolean optimized_view;
199 /* Whether this was created via the *_new_for_search_result() function. */
200 gboolean is_search_result;
202 /* A reference to the @model of the header view
203 * to allow selecting previous/next messages,
204 * if the message is currently selected in the header view.
206 const gchar *header_folder_id;
207 GtkTreeModel *header_model;
208 GtkTreeRowReference *row_reference;
209 GtkTreeRowReference *next_row_reference;
211 gulong clipboard_change_handler;
212 gulong queue_change_handler;
213 gulong account_removed_handler;
214 gulong row_changed_handler;
215 gulong row_deleted_handler;
216 gulong row_inserted_handler;
217 gulong rows_reordered_handler;
220 GtkWidget *remove_attachment_banner;
222 guint progress_bar_timeout;
227 #define MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
228 MODEST_TYPE_MSG_VIEW_WINDOW, \
229 ModestMsgViewWindowPrivate))
231 static GtkWindowClass *parent_class = NULL;
233 /* uncomment the following if you have defined any signals */
234 static guint signals[LAST_SIGNAL] = {0};
237 modest_msg_view_window_get_type (void)
239 static GType my_type = 0;
241 static const GTypeInfo my_info = {
242 sizeof(ModestMsgViewWindowClass),
243 NULL, /* base init */
244 NULL, /* base finalize */
245 (GClassInitFunc) modest_msg_view_window_class_init,
246 NULL, /* class finalize */
247 NULL, /* class data */
248 sizeof(ModestMsgViewWindow),
250 (GInstanceInitFunc) modest_msg_view_window_init,
253 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
254 "ModestMsgViewWindow",
257 static const GInterfaceInfo modest_header_view_observer_info =
259 (GInterfaceInitFunc) modest_header_view_observer_init,
260 NULL, /* interface_finalize */
261 NULL /* interface_data */
264 g_type_add_interface_static (my_type,
265 MODEST_TYPE_HEADER_VIEW_OBSERVER,
266 &modest_header_view_observer_info);
272 save_state (ModestWindow *self)
274 modest_widget_memory_save (modest_runtime_get_conf (),
276 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
281 restore_settings (ModestMsgViewWindow *self)
283 modest_widget_memory_restore (modest_runtime_get_conf (),
285 MODEST_CONF_MSG_VIEW_WINDOW_KEY);
289 modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass)
291 GObjectClass *gobject_class;
292 ModestWindowClass *modest_window_class;
293 gobject_class = (GObjectClass*) klass;
294 modest_window_class = (ModestWindowClass *) klass;
296 parent_class = g_type_class_peek_parent (klass);
297 gobject_class->finalize = modest_msg_view_window_finalize;
299 modest_window_class->set_zoom_func = modest_msg_view_window_set_zoom;
300 modest_window_class->get_zoom_func = modest_msg_view_window_get_zoom;
301 modest_window_class->zoom_minus_func = modest_msg_view_window_zoom_minus;
302 modest_window_class->zoom_plus_func = modest_msg_view_window_zoom_plus;
303 modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar;
304 modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals;
306 g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate));
308 modest_window_class->save_state_func = save_state;
310 signals[MSG_CHANGED_SIGNAL] =
311 g_signal_new ("msg-changed",
312 G_TYPE_FROM_CLASS (gobject_class),
314 G_STRUCT_OFFSET (ModestMsgViewWindowClass, msg_changed),
316 modest_marshal_VOID__POINTER_POINTER,
317 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
320 static void modest_header_view_observer_init(
321 ModestHeaderViewObserverIface *iface_class)
323 iface_class->update_func = modest_msg_view_window_update_model_replaced;
327 modest_msg_view_window_init (ModestMsgViewWindow *obj)
329 ModestMsgViewWindowPrivate *priv;
330 ModestWindowPrivate *parent_priv = NULL;
331 GtkActionGroup *action_group = NULL;
332 GError *error = NULL;
333 GdkPixbuf *window_icon;
335 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
336 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
337 parent_priv->ui_manager = gtk_ui_manager_new();
339 action_group = gtk_action_group_new ("ModestMsgViewWindowActions");
340 gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
342 /* Add common actions */
343 gtk_action_group_add_actions (action_group,
344 modest_action_entries,
345 G_N_ELEMENTS (modest_action_entries),
347 gtk_action_group_add_toggle_actions (action_group,
348 modest_toggle_action_entries,
349 G_N_ELEMENTS (modest_toggle_action_entries),
351 gtk_action_group_add_toggle_actions (action_group,
352 msg_view_toggle_action_entries,
353 G_N_ELEMENTS (msg_view_toggle_action_entries),
355 gtk_action_group_add_radio_actions (action_group,
356 msg_view_zoom_action_entries,
357 G_N_ELEMENTS (msg_view_zoom_action_entries),
359 G_CALLBACK (modest_ui_actions_on_change_zoom),
362 gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
363 g_object_unref (action_group);
365 /* Load the UI definition */
366 gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager, MODEST_UIDIR "modest-msg-view-window-ui.xml",
369 g_printerr ("modest: could not merge modest-msg-view-window-ui.xml: %s\n", error->message);
370 g_error_free (error);
375 /* Add accelerators */
376 gtk_window_add_accel_group (GTK_WINDOW (obj),
377 gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
379 priv->is_search_result = FALSE;
381 priv->msg_view = NULL;
382 priv->header_model = NULL;
383 priv->header_folder_id = NULL;
384 priv->clipboard_change_handler = 0;
385 priv->queue_change_handler = 0;
386 priv->account_removed_handler = 0;
387 priv->row_changed_handler = 0;
388 priv->row_deleted_handler = 0;
389 priv->row_inserted_handler = 0;
390 priv->rows_reordered_handler = 0;
391 priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
393 priv->optimized_view = FALSE;
394 priv->progress_bar_timeout = 0;
395 priv->purge_timeout = 0;
396 priv->remove_attachment_banner = NULL;
397 priv->msg_uid = NULL;
400 init_window (MODEST_MSG_VIEW_WINDOW(obj));
401 /* Set window icon */
402 window_icon = modest_platform_get_icon (MODEST_APP_MSG_VIEW_ICON);
404 gtk_window_set_icon (GTK_WINDOW (obj), window_icon);
405 g_object_unref (window_icon);
409 modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
410 GTK_WINDOW(obj),"applications_email_viewer");
415 set_toolbar_transfer_mode (ModestMsgViewWindow *self)
417 ModestMsgViewWindowPrivate *priv = NULL;
419 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
421 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
423 set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
425 if (priv->progress_bar_timeout > 0) {
426 g_source_remove (priv->progress_bar_timeout);
427 priv->progress_bar_timeout = 0;
434 set_toolbar_mode (ModestMsgViewWindow *self,
435 ModestToolBarModes mode)
437 ModestWindowPrivate *parent_priv;
438 ModestMsgViewWindowPrivate *priv;
439 /* GtkWidget *widget = NULL; */
441 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
443 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
444 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
446 /* Sets current toolbar mode */
447 priv->current_toolbar_mode = mode;
449 /* Update toolbar dimming state */
450 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
453 case TOOLBAR_MODE_NORMAL:
454 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
455 /* gtk_action_set_sensitive (widget, TRUE); */
456 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
457 /* gtk_action_set_sensitive (widget, TRUE); */
458 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
459 /* gtk_action_set_sensitive (widget, TRUE); */
460 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
461 /* gtk_action_set_sensitive (widget, TRUE); */
463 if (priv->prev_toolitem)
464 gtk_widget_show (priv->prev_toolitem);
466 if (priv->next_toolitem)
467 gtk_widget_show (priv->next_toolitem);
469 if (priv->progress_toolitem)
470 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
471 if (priv->progress_bar)
472 gtk_widget_hide (priv->progress_bar);
474 if (priv->cancel_toolitem)
475 gtk_widget_hide (priv->cancel_toolitem);
477 /* Hide toolbar if optimized view is enabled */
478 if (priv->optimized_view) {
479 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
480 gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
484 case TOOLBAR_MODE_TRANSFER:
485 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply"); */
486 /* gtk_action_set_sensitive (widget, FALSE); */
487 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage"); */
488 /* gtk_action_set_sensitive (widget, FALSE); */
489 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarMessageMoveTo"); */
490 /* gtk_action_set_sensitive (widget, FALSE); */
491 /* widget = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"); */
492 /* gtk_action_set_sensitive (widget, FALSE); */
494 if (priv->prev_toolitem)
495 gtk_widget_hide (priv->prev_toolitem);
497 if (priv->next_toolitem)
498 gtk_widget_hide (priv->next_toolitem);
500 if (priv->progress_toolitem)
501 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
502 if (priv->progress_bar)
503 gtk_widget_show (priv->progress_bar);
505 if (priv->cancel_toolitem)
506 gtk_widget_show (priv->cancel_toolitem);
508 /* Show toolbar if it's hiden (optimized view ) */
509 if (priv->optimized_view) {
510 gtk_widget_set_no_show_all (parent_priv->toolbar, FALSE);
511 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
516 g_return_if_reached ();
523 menubar_to_menu (GtkUIManager *ui_manager)
525 GtkWidget *main_menu;
527 GList *iter, *children;
529 /* Create new main menu */
530 main_menu = gtk_menu_new();
532 /* Get the menubar from the UI manager */
533 menubar = gtk_ui_manager_get_widget (ui_manager, "/MenuBar");
535 iter = children = gtk_container_get_children (GTK_CONTAINER (menubar));
539 menu = GTK_WIDGET (iter->data);
540 gtk_widget_reparent(menu, main_menu);
542 iter = g_list_next (iter);
544 g_list_free (children);
550 init_window (ModestMsgViewWindow *obj)
552 GtkWidget *main_vbox;
553 ModestMsgViewWindowPrivate *priv;
554 ModestWindowPrivate *parent_priv;
556 GtkAction *action = NULL;
558 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
559 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
561 priv->msg_view = GTK_WIDGET (tny_platform_factory_new_msg_view (modest_tny_platform_factory_get_instance ()));
562 modest_msg_view_set_shadow_type (MODEST_MSG_VIEW (priv->msg_view), GTK_SHADOW_NONE);
563 main_vbox = gtk_vbox_new (FALSE, 6);
566 parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager);
567 conf = modest_runtime_get_conf ();
568 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
569 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu");
570 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
571 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR, NULL));
572 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
573 "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu");
574 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
575 modest_conf_get_bool (conf, MODEST_CONF_MSG_VIEW_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
576 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(parent_priv->menubar));
577 gtk_widget_show (GTK_WIDGET(parent_priv->menubar));
579 #ifdef MODEST_USE_MOZEMBED
580 priv->main_scroll = priv->msg_view;
581 gtk_widget_set_size_request (priv->msg_view, -1, 1600);
583 priv->main_scroll = gtk_scrolled_window_new (NULL, NULL);
584 gtk_container_add (GTK_CONTAINER (priv->main_scroll), priv->msg_view);
586 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
587 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->main_scroll), GTK_SHADOW_NONE);
588 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->main_scroll), TRUE);
590 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_scroll, TRUE, TRUE, 0);
591 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
593 priv->find_toolbar = hildon_find_toolbar_new (NULL);
594 hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (priv->find_toolbar));
595 gtk_widget_set_no_show_all (priv->find_toolbar, TRUE);
596 g_signal_connect (G_OBJECT (priv->find_toolbar), "close", G_CALLBACK (modest_msg_view_window_find_toolbar_close), obj);
597 g_signal_connect (G_OBJECT (priv->find_toolbar), "search", G_CALLBACK (modest_msg_view_window_find_toolbar_search), obj);
599 gtk_widget_show_all (GTK_WIDGET(main_vbox));
603 modest_msg_view_window_disconnect_signals (ModestWindow *self)
605 ModestMsgViewWindowPrivate *priv;
606 ModestHeaderView *header_view = NULL;
607 ModestWindow *main_window = NULL;
609 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
611 if (gtk_clipboard_get (GDK_SELECTION_PRIMARY) &&
612 g_signal_handler_is_connected (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
613 priv->clipboard_change_handler))
614 g_signal_handler_disconnect (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
615 priv->clipboard_change_handler);
617 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
618 priv->queue_change_handler))
619 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
620 priv->queue_change_handler);
622 if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_account_store ()),
623 priv->account_removed_handler))
624 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_account_store ()),
625 priv->account_removed_handler);
627 if (priv->header_model) {
628 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
629 priv->row_changed_handler))
630 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
631 priv->row_changed_handler);
633 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
634 priv->row_deleted_handler))
635 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
636 priv->row_deleted_handler);
638 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
639 priv->row_inserted_handler))
640 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
641 priv->row_inserted_handler);
643 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
644 priv->rows_reordered_handler))
645 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
646 priv->rows_reordered_handler);
649 main_window = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(),
650 FALSE); /* don't create */
654 header_view = MODEST_HEADER_VIEW(
655 modest_main_window_get_child_widget(
656 MODEST_MAIN_WINDOW(main_window),
657 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
658 if (header_view == NULL)
661 modest_header_view_remove_observer(header_view,
662 MODEST_HEADER_VIEW_OBSERVER(self));
666 modest_msg_view_window_finalize (GObject *obj)
668 ModestMsgViewWindowPrivate *priv;
670 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
672 /* Sanity check: shouldn't be needed, the window mgr should
673 call this function before */
674 modest_msg_view_window_disconnect_signals (MODEST_WINDOW (obj));
676 if (priv->header_model != NULL) {
677 g_object_unref (priv->header_model);
678 priv->header_model = NULL;
681 if (priv->progress_bar_timeout > 0) {
682 g_source_remove (priv->progress_bar_timeout);
683 priv->progress_bar_timeout = 0;
686 if (priv->remove_attachment_banner) {
687 gtk_widget_destroy (priv->remove_attachment_banner);
688 g_object_unref (priv->remove_attachment_banner);
689 priv->remove_attachment_banner = NULL;
692 if (priv->purge_timeout > 0) {
693 g_source_remove (priv->purge_timeout);
694 priv->purge_timeout = 0;
697 if (priv->row_reference) {
698 gtk_tree_row_reference_free (priv->row_reference);
699 priv->row_reference = NULL;
702 if (priv->next_row_reference) {
703 gtk_tree_row_reference_free (priv->next_row_reference);
704 priv->next_row_reference = NULL;
708 g_free (priv->msg_uid);
709 priv->msg_uid = NULL;
712 G_OBJECT_CLASS(parent_class)->finalize (obj);
716 select_next_valid_row (GtkTreeModel *model,
717 GtkTreeRowReference **row_reference,
720 GtkTreeIter tmp_iter;
721 GtkTreePath *path, *next;
722 gboolean retval = FALSE;
724 g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE);
726 path = gtk_tree_row_reference_get_path (*row_reference);
727 gtk_tree_model_get_iter (model, &tmp_iter, path);
728 gtk_tree_row_reference_free (*row_reference);
729 *row_reference = NULL;
731 if (gtk_tree_model_iter_next (model, &tmp_iter)) {
732 next = gtk_tree_model_get_path (model, &tmp_iter);
733 *row_reference = gtk_tree_row_reference_new (model, next);
735 } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) {
736 next = gtk_tree_model_get_path (model, &tmp_iter);
738 /* Ensure that we are not selecting the same */
739 if (gtk_tree_path_compare (path, next) != 0) {
740 *row_reference = gtk_tree_row_reference_new (model, next);
746 gtk_tree_path_free (path);
751 /* TODO: This should be in _init(), with the parameters as properties. */
753 modest_msg_view_window_construct (ModestMsgViewWindow *self,
754 const gchar *modest_account_name,
755 const gchar *msg_uid)
758 ModestMsgViewWindowPrivate *priv = NULL;
759 ModestWindowPrivate *parent_priv = NULL;
760 ModestDimmingRulesGroup *menu_rules_group = NULL;
761 ModestDimmingRulesGroup *toolbar_rules_group = NULL;
762 ModestDimmingRulesGroup *clipboard_rules_group = NULL;
764 obj = G_OBJECT (self);
765 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(obj);
766 parent_priv = MODEST_WINDOW_GET_PRIVATE(obj);
768 priv->msg_uid = g_strdup (msg_uid);
770 parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
772 menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
773 toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
774 clipboard_rules_group = modest_dimming_rules_group_new ("ModestClipboardDimmingRules", FALSE);
776 /* Add common dimming rules */
777 modest_dimming_rules_group_add_rules (menu_rules_group,
778 modest_msg_view_menu_dimming_entries,
779 G_N_ELEMENTS (modest_msg_view_menu_dimming_entries),
780 MODEST_WINDOW (self));
781 modest_dimming_rules_group_add_rules (toolbar_rules_group,
782 modest_msg_view_toolbar_dimming_entries,
783 G_N_ELEMENTS (modest_msg_view_toolbar_dimming_entries),
784 MODEST_WINDOW (self));
785 modest_dimming_rules_group_add_rules (clipboard_rules_group,
786 modest_msg_view_clipboard_dimming_entries,
787 G_N_ELEMENTS (modest_msg_view_clipboard_dimming_entries),
788 MODEST_WINDOW (self));
790 /* Insert dimming rules group for this window */
791 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
792 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
793 modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, clipboard_rules_group);
794 g_object_unref (menu_rules_group);
795 g_object_unref (toolbar_rules_group);
796 g_object_unref (clipboard_rules_group);
798 restore_settings (MODEST_MSG_VIEW_WINDOW(obj));
800 /* g_signal_connect (G_OBJECT(obj), "delete-event", G_CALLBACK(on_delete_event), obj); */
802 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);
803 g_signal_connect (G_OBJECT(priv->msg_view), "activate_link",
804 G_CALLBACK (modest_ui_actions_on_msg_link_clicked), obj);
805 g_signal_connect (G_OBJECT(priv->msg_view), "link_hover",
806 G_CALLBACK (modest_ui_actions_on_msg_link_hover), obj);
807 g_signal_connect (G_OBJECT(priv->msg_view), "attachment_clicked",
808 G_CALLBACK (modest_ui_actions_on_msg_attachment_clicked), obj);
809 g_signal_connect (G_OBJECT(priv->msg_view), "recpt_activated",
810 G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj);
811 g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual",
812 G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj);
814 g_signal_connect (G_OBJECT (obj), "key-release-event",
815 G_CALLBACK (modest_msg_view_window_key_release_event),
818 g_signal_connect (G_OBJECT (obj), "window-state-event",
819 G_CALLBACK (modest_msg_view_window_window_state_event),
822 g_signal_connect (G_OBJECT (obj), "move-focus",
823 G_CALLBACK (on_move_focus), obj);
825 /* Mail Operation Queue */
826 priv->queue_change_handler = g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
828 G_CALLBACK (on_queue_changed),
831 /* Account manager */
832 priv->account_removed_handler = g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
834 G_CALLBACK(on_account_removed),
837 modest_window_set_active_account (MODEST_WINDOW(obj), modest_account_name);
839 priv->last_search = NULL;
841 /* Init the clipboard actions dim status */
842 modest_msg_view_grab_focus(MODEST_MSG_VIEW (priv->msg_view));
844 update_window_title (MODEST_MSG_VIEW_WINDOW (obj));
846 /* Check toolbar dimming rules */
847 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (obj));
848 modest_window_check_dimming_rules_group (MODEST_WINDOW (obj), "ModestClipboardDimmingRules");
852 /* FIXME: parameter checks */
854 modest_msg_view_window_new_with_header_model (TnyMsg *msg,
855 const gchar *modest_account_name,
856 const gchar *msg_uid,
858 GtkTreeRowReference *row_reference)
860 ModestMsgViewWindow *window = NULL;
861 ModestMsgViewWindowPrivate *priv = NULL;
862 TnyFolder *header_folder = NULL;
863 ModestHeaderView *header_view = NULL;
864 ModestWindow *main_window = NULL;
865 ModestWindowMgr *mgr = NULL;
867 mgr = modest_runtime_get_window_mgr ();
868 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
869 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
871 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
873 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
875 /* Remember the message list's TreeModel so we can detect changes
876 * and change the list selection when necessary: */
878 main_window = modest_window_mgr_get_main_window(mgr, FALSE); /* don't create */
880 g_warning ("%s: BUG: no main window", __FUNCTION__);
884 header_view = MODEST_HEADER_VIEW(modest_main_window_get_child_widget(
885 MODEST_MAIN_WINDOW(main_window),
886 MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW));
887 if (header_view != NULL){
888 header_folder = modest_header_view_get_folder(header_view);
889 g_assert(header_folder != NULL);
890 priv->header_folder_id = tny_folder_get_id(header_folder);
891 g_assert(priv->header_folder_id != NULL);
892 g_object_unref(header_folder);
895 priv->header_model = g_object_ref(model);
896 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
897 priv->next_row_reference = gtk_tree_row_reference_copy (row_reference);
898 select_next_valid_row (model, &(priv->next_row_reference), TRUE);
900 priv->row_changed_handler = g_signal_connect(
901 GTK_TREE_MODEL(model), "row-changed",
902 G_CALLBACK(modest_msg_view_window_on_row_changed),
904 priv->row_deleted_handler = g_signal_connect(
905 GTK_TREE_MODEL(model), "row-deleted",
906 G_CALLBACK(modest_msg_view_window_on_row_deleted),
908 priv->row_inserted_handler = g_signal_connect (
909 GTK_TREE_MODEL(model), "row-inserted",
910 G_CALLBACK(modest_msg_view_window_on_row_inserted),
912 priv->rows_reordered_handler = g_signal_connect(
913 GTK_TREE_MODEL(model), "rows-reordered",
914 G_CALLBACK(modest_msg_view_window_on_row_reordered),
917 if (header_view != NULL){
918 modest_header_view_add_observer(header_view,
919 MODEST_HEADER_VIEW_OBSERVER(window));
922 gtk_widget_show_all (GTK_WIDGET (window));
924 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
925 update_window_title (MODEST_MSG_VIEW_WINDOW (window));
927 modest_msg_view_window_update_priority (window);
929 /* Check toolbar dimming rules */
930 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
932 return MODEST_WINDOW(window);
936 modest_msg_view_window_new_for_search_result (TnyMsg *msg,
937 const gchar *modest_account_name,
938 const gchar *msg_uid)
940 ModestMsgViewWindow *window = NULL;
941 ModestMsgViewWindowPrivate *priv = NULL;
942 ModestWindowMgr *mgr = NULL;
944 mgr = modest_runtime_get_window_mgr ();
945 window = MODEST_MSG_VIEW_WINDOW (modest_window_mgr_get_msg_view_window (mgr));
946 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), NULL);
947 modest_msg_view_window_construct (window, modest_account_name, msg_uid);
949 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
951 /* Remember that this is a search result,
952 * so we can disable some UI appropriately: */
953 priv->is_search_result = TRUE;
955 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
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);
978 return MODEST_WINDOW(obj);
981 void modest_msg_view_window_on_row_changed(
982 GtkTreeModel *header_model,
985 ModestMsgViewWindow *window){
986 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
989 void modest_msg_view_window_on_row_deleted(
990 GtkTreeModel *header_model,
992 ModestMsgViewWindow *window){
993 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
996 /* On insertions we check if the folder still has the message we are
997 * showing or do not. If do not, we do nothing. Which means we are still
998 * not attached to any header folder and thus next/prev buttons are
999 * still dimmed. Once the message that is shown by msg-view is found, the
1000 * new model of header-view will be attached and the references will be set.
1001 * On each further insertions dimming rules will be checked. However
1002 * this requires extra CPU time at least works.
1003 * (An message might be deleted from TnyFolder and thus will not be
1004 * inserted into the model again for example if it is removed by the
1005 * imap server and the header view is refreshed.)
1007 void modest_msg_view_window_on_row_inserted(
1008 GtkTreeModel *new_model,
1009 GtkTreePath *tree_path,
1010 GtkTreeIter *tree_iter,
1011 ModestMsgViewWindow *window){
1012 ModestMsgViewWindowPrivate *priv = NULL;
1013 TnyHeader *header = NULL;
1016 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1018 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1020 /* If we already has a model attached then the message shown by
1021 * msg-view is in it, and thus we do not need any actions but
1022 * to check the dimming rules.*/
1023 if(priv->header_model != NULL){
1024 gtk_tree_row_reference_free(priv->next_row_reference);
1025 priv->next_row_reference = gtk_tree_row_reference_copy(
1026 priv->row_reference);
1027 select_next_valid_row (priv->header_model,
1028 &(priv->next_row_reference), FALSE);
1029 modest_ui_actions_check_toolbar_dimming_rules (
1030 MODEST_WINDOW (window));
1034 /* Check if the newly inserted message is the same we are actually
1035 * showing. IF not, we should remain detached from the header model
1036 * and thus prev and next toolbarbuttons should remain dimmed. */
1037 gtk_tree_model_get (new_model, tree_iter,
1038 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &header, -1);
1039 uid = modest_tny_folder_get_header_unique_id(header);
1040 if(!g_str_equal(priv->msg_uid, uid)){
1046 /* Setup row_reference for the actual msg. */
1047 priv->row_reference = gtk_tree_row_reference_new(
1048 new_model, tree_path);
1049 if(priv->row_reference == NULL){
1050 g_warning("No reference for msg header item.");
1054 /* Attach new_model and connect some callback to it to become able
1055 * to detect changes in header-view. */
1056 priv->header_model = g_object_ref(new_model);
1057 g_signal_connect (new_model, "row-changed",
1058 G_CALLBACK (modest_msg_view_window_on_row_changed),
1060 g_signal_connect (new_model, "row-deleted",
1061 G_CALLBACK (modest_msg_view_window_on_row_deleted),
1063 g_signal_connect (new_model, "rows-reordered",
1064 G_CALLBACK (modest_msg_view_window_on_row_reordered),
1067 /* Now set up next_row_reference. */
1068 priv->next_row_reference = gtk_tree_row_reference_copy(
1069 priv->row_reference);
1070 select_next_valid_row (priv->header_model,
1071 &(priv->next_row_reference), FALSE);
1073 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1076 void modest_msg_view_window_on_row_reordered(
1077 GtkTreeModel *header_model,
1081 ModestMsgViewWindow *window){
1082 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1085 /* The modest_msg_view_window_update_model_replaced implements update
1086 * function for ModestHeaderViewObserver. Checks whether the TnyFolder
1087 * actually belongs to the header-view is the same as the TnyFolder of
1088 * the message of msg-view or not. If they are different, there is
1089 * nothing to do. If they are the same, then the model has replaced and
1090 * the reference in msg-view shall be replaced from the old model to
1091 * the new model. In this case the view will be detached from it's
1092 * header folder. From this point the next/prev buttons are dimmed.
1094 void modest_msg_view_window_update_model_replaced(
1095 ModestHeaderViewObserver *observer,
1096 GtkTreeModel *model,
1097 const gchar *tny_folder_id){
1098 ModestMsgViewWindowPrivate *priv = NULL;
1099 ModestMsgViewWindow *window = NULL;
1101 g_assert(MODEST_IS_HEADER_VIEW_OBSERVER(observer));
1102 g_assert(MODEST_IS_MSG_VIEW_WINDOW(observer));
1104 window = MODEST_MSG_VIEW_WINDOW(observer);
1105 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(window);
1107 /* If there is an other folder in the header-view then we do
1108 * not care about it's model (msg list). Else if the
1109 * header-view shows the folder the msg shown by us is in, we
1110 * shall replace our model reference and make some check. */
1111 if(tny_folder_id == NULL || !g_str_equal(tny_folder_id, priv->header_folder_id))
1114 /* Model is changed(replaced), so we should forget the old
1115 * one. Because there might be other references and there
1116 * might be some change on the model even if we unreferenced
1117 * it, we need to disconnect our signals here. */
1118 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1119 priv->row_changed_handler))
1120 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1121 priv->row_changed_handler);
1122 priv->row_changed_handler = 0;
1123 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1124 priv->row_deleted_handler))
1125 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1126 priv->row_deleted_handler);
1127 priv->row_deleted_handler = 0;
1128 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1129 priv->row_inserted_handler))
1130 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1131 priv->row_inserted_handler);
1132 priv->row_inserted_handler = 0;
1133 if (g_signal_handler_is_connected(G_OBJECT (priv->header_model),
1134 priv->rows_reordered_handler))
1135 g_signal_handler_disconnect(G_OBJECT (priv->header_model),
1136 priv->rows_reordered_handler);
1137 priv->rows_reordered_handler = 0;
1138 g_object_unref(priv->header_model);
1139 priv->header_model = NULL;
1140 g_object_unref(priv->row_reference);
1141 priv->row_reference = NULL;
1142 g_object_unref(priv->next_row_reference);
1143 priv->next_row_reference = NULL;
1145 modest_ui_actions_check_toolbar_dimming_rules(MODEST_WINDOW(window));
1147 g_assert(model != NULL);
1149 /* Also we must connect to the new model for row insertions.
1150 * Only for insertions now. We will need other ones only after
1151 * the msg is show by msg-view is added to the new model. */
1152 priv->row_inserted_handler = g_signal_connect (
1153 model, "row-inserted",
1154 G_CALLBACK(modest_msg_view_window_on_row_inserted),
1159 modest_msg_view_window_toolbar_on_transfer_mode (ModestMsgViewWindow *self)
1161 ModestMsgViewWindowPrivate *priv= NULL;
1163 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1164 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1166 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1170 modest_msg_view_window_get_header (ModestMsgViewWindow *self)
1172 ModestMsgViewWindowPrivate *priv= NULL;
1174 TnyHeader *header = NULL;
1175 GtkTreePath *path = NULL;
1178 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), NULL);
1179 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1181 /* If the message was not obtained from a treemodel,
1182 * for instance if it was opened directly by the search UI:
1184 if (priv->header_model == NULL) {
1185 msg = modest_msg_view_window_get_message (self);
1187 header = tny_msg_get_header (msg);
1188 g_object_unref (msg);
1193 /* Get iter of the currently selected message in the header view: */
1194 /* TODO: Why not just give this window a ref of the TnyHeader or TnyMessage,
1195 * instead of sometimes retrieving it from the header view?
1196 * Then we wouldn't be dependent on the message actually still being selected
1197 * in the header view. murrayc. */
1198 if (!gtk_tree_row_reference_valid (priv->row_reference))
1200 path = gtk_tree_row_reference_get_path (priv->row_reference);
1201 g_return_val_if_fail (path != NULL, NULL);
1202 gtk_tree_model_get_iter (priv->header_model,
1206 /* Get current message header */
1207 gtk_tree_model_get (priv->header_model, &iter,
1208 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1211 gtk_tree_path_free (path);
1216 modest_msg_view_window_get_message (ModestMsgViewWindow *self)
1218 ModestMsgViewWindowPrivate *priv;
1220 g_return_val_if_fail (self, NULL);
1222 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1224 return tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1228 modest_msg_view_window_get_message_uid (ModestMsgViewWindow *self)
1230 ModestMsgViewWindowPrivate *priv;
1232 g_return_val_if_fail (self, NULL);
1234 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1236 return (const gchar*) priv->msg_uid;
1240 modest_msg_view_window_toggle_find_toolbar (GtkToggleAction *toggle,
1243 ModestMsgViewWindow *window = MODEST_MSG_VIEW_WINDOW (data);
1244 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1245 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1249 is_active = gtk_toggle_action_get_active (toggle);
1252 gtk_widget_show (priv->find_toolbar);
1253 hildon_find_toolbar_highlight_entry (HILDON_FIND_TOOLBAR (priv->find_toolbar), TRUE);
1255 gtk_widget_hide (priv->find_toolbar);
1258 /* update the toggle buttons status */
1259 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage");
1260 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1261 action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ToolsMenu/ToolsFindInMessageMenu");
1262 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), is_active);
1267 modest_msg_view_window_find_toolbar_close (GtkWidget *widget,
1268 ModestMsgViewWindow *obj)
1270 GtkToggleAction *toggle;
1271 ModestWindowPrivate *parent_priv;
1272 parent_priv = MODEST_WINDOW_GET_PRIVATE (obj);
1274 toggle = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/FindInMessage"));
1275 gtk_toggle_action_set_active (toggle, FALSE);
1279 modest_msg_view_window_find_toolbar_search (GtkWidget *widget,
1280 ModestMsgViewWindow *obj)
1282 gchar *current_search;
1283 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (obj);
1285 if (modest_mime_part_view_is_empty (MODEST_MIME_PART_VIEW (priv->msg_view))) {
1286 hildon_banner_show_information (NULL, NULL, _("mail_ib_nothing_to_find"));
1290 g_object_get (G_OBJECT (widget), "prefix", ¤t_search, NULL);
1292 if ((current_search == NULL) || (strcmp (current_search, "") == 0)) {
1293 g_free (current_search);
1294 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ecdg_ib_find_rep_enter_text"));
1298 if ((priv->last_search == NULL) || (strcmp (priv->last_search, current_search) != 0)) {
1300 g_free (priv->last_search);
1301 priv->last_search = g_strdup (current_search);
1302 result = modest_isearch_view_search (MODEST_ISEARCH_VIEW (priv->msg_view),
1305 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_no_matches"));
1306 g_free (priv->last_search);
1307 priv->last_search = NULL;
1309 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1312 if (!modest_isearch_view_search_next (MODEST_ISEARCH_VIEW (priv->msg_view))) {
1313 hildon_banner_show_information (NULL, NULL, dgettext("hildon-libs", "ckct_ib_find_search_complete"));
1314 g_free (priv->last_search);
1315 priv->last_search = NULL;
1317 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1321 g_free (current_search);
1326 modest_msg_view_window_set_zoom (ModestWindow *window,
1329 ModestMsgViewWindowPrivate *priv;
1330 ModestWindowPrivate *parent_priv;
1331 GtkAction *action = NULL;
1332 gint int_zoom = (gint) rint (zoom*100.0+0.1);
1334 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
1336 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1337 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1338 modest_zoomable_set_zoom (MODEST_ZOOMABLE (priv->msg_view), zoom);
1340 action = gtk_ui_manager_get_action (parent_priv->ui_manager,
1341 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu");
1343 gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), int_zoom);
1347 modest_msg_view_window_get_zoom (ModestWindow *window)
1349 ModestMsgViewWindowPrivate *priv;
1351 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), 1.0);
1353 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1354 return modest_zoomable_get_zoom (MODEST_ZOOMABLE (priv->msg_view));
1358 modest_msg_view_window_zoom_plus (ModestWindow *window)
1360 ModestWindowPrivate *parent_priv;
1361 GtkRadioAction *zoom_radio_action;
1362 GSList *group, *node;
1364 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1365 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1366 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1368 group = gtk_radio_action_get_group (zoom_radio_action);
1370 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (group->data))) {
1371 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_max_zoom_level_reached"));
1375 for (node = group; node != NULL; node = g_slist_next (node)) {
1376 if ((node->next != NULL) && gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->next->data))) {
1377 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->data), TRUE);
1385 modest_msg_view_window_zoom_minus (ModestWindow *window)
1387 ModestWindowPrivate *parent_priv;
1388 GtkRadioAction *zoom_radio_action;
1389 GSList *group, *node;
1391 parent_priv = MODEST_WINDOW_GET_PRIVATE (window);
1392 zoom_radio_action = GTK_RADIO_ACTION (gtk_ui_manager_get_action (parent_priv->ui_manager,
1393 "/MenuBar/ViewMenu/ZoomMenu/Zoom50Menu"));
1395 group = gtk_radio_action_get_group (zoom_radio_action);
1397 for (node = group; node != NULL; node = g_slist_next (node)) {
1398 if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (node->data))) {
1399 if (node->next != NULL) {
1400 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (node->next->data), TRUE);
1403 hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_min_zoom_level_reached"));
1413 modest_msg_view_window_key_release_event (GtkWidget *window,
1417 if (event->type == GDK_KEY_RELEASE) {
1418 switch (event->keyval) {
1420 modest_msg_view_window_scroll_up (MODEST_WINDOW (window));
1424 modest_msg_view_window_scroll_down (MODEST_WINDOW (window));
1437 modest_msg_view_window_scroll_up (ModestWindow *window)
1439 ModestMsgViewWindowPrivate *priv;
1440 gboolean return_value;
1442 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1443 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, &return_value);
1447 modest_msg_view_window_scroll_down (ModestWindow *window)
1449 ModestMsgViewWindowPrivate *priv;
1450 gboolean return_value;
1452 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1453 g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, &return_value);
1457 modest_msg_view_window_last_message_selected (ModestMsgViewWindow *window)
1460 ModestMsgViewWindowPrivate *priv;
1461 GtkTreeIter tmp_iter;
1462 gboolean is_last_selected;
1464 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1465 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1467 /*if no model (so no rows at all), then virtually we are the last*/
1468 if (!priv->header_model)
1471 path = gtk_tree_row_reference_get_path (priv->row_reference);
1475 is_last_selected = TRUE;
1476 while (is_last_selected) {
1478 gtk_tree_path_next (path);
1479 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1481 gtk_tree_model_get (priv->header_model, &tmp_iter,
1482 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1484 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1485 is_last_selected = FALSE;
1487 gtk_tree_path_free (path);
1488 return is_last_selected;
1492 modest_msg_view_window_has_headers_model (ModestMsgViewWindow *window)
1494 ModestMsgViewWindowPrivate *priv;
1496 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1497 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1499 return priv->header_model != NULL;
1503 modest_msg_view_window_is_search_result (ModestMsgViewWindow *window)
1505 ModestMsgViewWindowPrivate *priv;
1507 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1508 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1510 return priv->is_search_result;
1514 modest_msg_view_window_first_message_selected (ModestMsgViewWindow *window)
1517 ModestMsgViewWindowPrivate *priv;
1518 gboolean is_first_selected;
1519 GtkTreeIter tmp_iter;
1520 /* gchar * path_string;*/
1522 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), TRUE);
1523 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1525 /*if no model (so no rows at all), then virtually we are the first*/
1526 if (!priv->header_model)
1529 path = gtk_tree_row_reference_get_path (priv->row_reference);
1533 /* path_string = gtk_tree_path_to_string (path);
1534 is_first_selected = strcmp (path_string, "0");
1536 g_free (path_string);
1537 gtk_tree_path_free (path);
1539 return is_first_selected;*/
1541 is_first_selected = TRUE;
1542 while (is_first_selected) {
1544 if(!gtk_tree_path_prev (path))
1546 /* Here the 'if' is needless for logic, but let make sure
1547 * iter is valid for gtk_tree_model_get. */
1548 if (!gtk_tree_model_get_iter (priv->header_model, &tmp_iter, path))
1550 gtk_tree_model_get (priv->header_model, &tmp_iter,
1551 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1553 if (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED))
1554 is_first_selected = FALSE;
1556 gtk_tree_path_free (path);
1557 return is_first_selected;
1561 * Reads the message whose summary item is @header. It takes care of
1562 * several things, among others:
1564 * If the message was not previously downloaded then ask the user
1565 * before downloading. If there is no connection launch the connection
1566 * dialog. Update toolbar dimming rules.
1568 * Returns: TRUE if the mail operation was started, otherwise if the
1569 * user do not want to download the message, or if the user do not
1570 * want to connect, then the operation is not issued
1573 message_reader (ModestMsgViewWindow *window,
1574 ModestMsgViewWindowPrivate *priv,
1576 GtkTreeRowReference *row_reference)
1578 ModestMailOperation *mail_op = NULL;
1579 ModestMailOperationTypeOperation op_type;
1580 gboolean already_showing = FALSE;
1581 ModestWindow *msg_window = NULL;
1582 ModestWindowMgr *mgr;
1584 g_return_val_if_fail (row_reference != NULL, FALSE);
1586 mgr = modest_runtime_get_window_mgr ();
1587 already_showing = modest_window_mgr_find_registered_header (mgr, header, &msg_window);
1588 if (already_showing && (msg_window != MODEST_WINDOW (window))) {
1591 gtk_window_present (GTK_WINDOW (msg_window));
1592 g_signal_emit_by_name (G_OBJECT (window), "delete-event", NULL, &retval);
1596 /* Msg download completed */
1597 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_CACHED) {
1598 op_type = MODEST_MAIL_OPERATION_TYPE_OPEN;
1600 op_type = MODEST_MAIL_OPERATION_TYPE_RECEIVE;
1602 /* Ask the user if he wants to download the message if
1604 if (!tny_device_is_online (modest_runtime_get_device())) {
1605 TnyFolder *folder = NULL;
1606 GtkResponseType response;
1608 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
1609 _("mcen_nc_get_msg"));
1610 if (response == GTK_RESPONSE_CANCEL)
1613 /* Offer the connection dialog if necessary */
1614 folder = tny_header_get_folder (header);
1616 if (!modest_platform_connect_and_wait_if_network_folderstore (NULL,
1617 TNY_FOLDER_STORE (folder))) {
1618 g_object_unref (folder);
1621 g_object_unref (folder);
1626 /* New mail operation */
1627 mail_op = modest_mail_operation_new_with_error_handling (G_OBJECT(window),
1628 modest_ui_actions_get_msgs_full_error_handler,
1631 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), mail_op);
1632 modest_mail_operation_get_msg (mail_op, header, view_msg_cb, row_reference);
1633 g_object_unref (mail_op);
1635 /* Update toolbar dimming rules */
1636 modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (window));
1642 modest_msg_view_window_select_next_message (ModestMsgViewWindow *window)
1644 ModestMsgViewWindowPrivate *priv;
1645 GtkTreePath *path= NULL;
1646 GtkTreeIter tmp_iter;
1648 gboolean retval = TRUE;
1649 GtkTreeRowReference *row_reference = NULL;
1651 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1652 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1654 /* Update the next row reference if it's not valid. This could
1655 happen if for example the header which it was pointing to,
1656 was deleted. The best place to do it is in the row-deleted
1657 handler but the tinymail model do not work like the glib
1658 tree models and reports the deletion when the row is still
1660 if (!gtk_tree_row_reference_valid (priv->next_row_reference)) {
1661 if (gtk_tree_row_reference_valid (priv->row_reference)) {
1662 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1663 select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE);
1666 if (priv->next_row_reference)
1667 path = gtk_tree_row_reference_get_path (priv->next_row_reference);
1671 row_reference = gtk_tree_row_reference_copy (priv->next_row_reference);
1673 gtk_tree_model_get_iter (priv->header_model,
1676 gtk_tree_path_free (path);
1678 gtk_tree_model_get (priv->header_model, &tmp_iter,
1679 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1682 /* Read the message & show it */
1683 if (!message_reader (window, priv, header, row_reference)) {
1685 gtk_tree_row_reference_free (row_reference);
1689 g_object_unref (header);
1695 modest_msg_view_window_select_first_message (ModestMsgViewWindow *self)
1697 ModestMsgViewWindowPrivate *priv = NULL;
1698 TnyHeader *header = NULL;
1700 GtkTreePath *path = NULL;
1701 GtkTreeRowReference *row_reference = NULL;
1703 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
1704 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1706 /* Check that the model is not empty */
1707 if (!gtk_tree_model_get_iter_first (priv->header_model, &iter))
1710 /* Get the header */
1711 gtk_tree_model_get (priv->header_model,
1713 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1715 g_return_val_if_fail (TNY_IS_HEADER (header), FALSE);
1716 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1717 g_object_unref (header);
1718 return modest_msg_view_window_select_next_message (self);
1721 path = gtk_tree_model_get_path (priv->header_model, &iter);
1722 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1723 gtk_tree_path_free (path);
1725 /* Read the message & show it */
1726 message_reader (self, priv, header, row_reference);
1729 g_object_unref (header);
1735 modest_msg_view_window_select_previous_message (ModestMsgViewWindow *window)
1737 ModestMsgViewWindowPrivate *priv = NULL;
1739 GtkTreeRowReference *row_reference = NULL;
1741 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window), FALSE);
1742 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1744 /* Return inmediatly if there is no header model */
1745 if (!priv->header_model)
1748 path = gtk_tree_row_reference_get_path (priv->row_reference);
1749 while (gtk_tree_path_prev (path)) {
1753 gtk_tree_model_get_iter (priv->header_model, &iter, path);
1754 gtk_tree_model_get (priv->header_model, &iter,
1755 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1759 if (tny_header_get_flags (header) & TNY_HEADER_FLAG_DELETED) {
1760 g_object_unref (header);
1764 row_reference = gtk_tree_row_reference_new (priv->header_model, path);
1765 /* Read the message & show it */
1766 if (!message_reader (window, priv, header, row_reference)) {
1767 gtk_tree_row_reference_free (row_reference);
1768 g_object_unref (header);
1772 gtk_tree_path_free (path);
1773 g_object_unref (header);
1778 gtk_tree_path_free (path);
1783 view_msg_cb (ModestMailOperation *mail_op,
1790 ModestMsgViewWindow *self = NULL;
1791 ModestMsgViewWindowPrivate *priv = NULL;
1792 GtkTreeRowReference *row_reference = NULL;
1794 /* If there was any error */
1795 row_reference = (GtkTreeRowReference *) user_data;
1796 if (!modest_ui_actions_msg_retrieval_check (mail_op, header, msg)) {
1797 gtk_tree_row_reference_free (row_reference);
1801 /* Get the window */
1802 self = (ModestMsgViewWindow *) modest_mail_operation_get_source (mail_op);
1803 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
1804 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (self);
1806 /* Update the row reference */
1807 gtk_tree_row_reference_free (priv->row_reference);
1808 priv->row_reference = gtk_tree_row_reference_copy (row_reference);
1809 priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference);
1810 select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE);
1811 gtk_tree_row_reference_free (row_reference);
1813 /* Mark header as read */
1814 if (!(tny_header_get_flags (header) & TNY_HEADER_FLAG_SEEN))
1815 tny_header_set_flag (header, TNY_HEADER_FLAG_SEEN);
1817 /* Set new message */
1818 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
1819 modest_msg_view_window_update_priority (self);
1820 update_window_title (MODEST_MSG_VIEW_WINDOW (self));
1821 modest_msg_view_grab_focus (MODEST_MSG_VIEW (priv->msg_view));
1823 /* Set the new message uid of the window */
1824 if (priv->msg_uid) {
1825 g_free (priv->msg_uid);
1826 priv->msg_uid = modest_tny_folder_get_header_unique_id (header);
1829 /* Notify the observers */
1830 g_signal_emit (G_OBJECT (self), signals[MSG_CHANGED_SIGNAL],
1831 0, priv->header_model, priv->row_reference);
1833 /* Free new references */
1834 g_object_unref (self);
1838 modest_msg_view_window_get_folder_type (ModestMsgViewWindow *window)
1840 ModestMsgViewWindowPrivate *priv;
1842 TnyFolderType folder_type;
1844 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1846 folder_type = TNY_FOLDER_TYPE_UNKNOWN;
1848 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
1852 folder = tny_msg_get_folder (msg);
1854 folder_type = tny_folder_get_folder_type (folder);
1855 g_object_unref (folder);
1857 g_object_unref (msg);
1865 modest_msg_view_window_update_priority (ModestMsgViewWindow *window)
1867 ModestMsgViewWindowPrivate *priv;
1868 TnyHeaderFlags flags = 0;
1870 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
1872 if (priv->header_model) {
1875 GtkTreePath *path = NULL;
1877 path = gtk_tree_row_reference_get_path (priv->row_reference);
1878 g_return_if_fail (path != NULL);
1879 gtk_tree_model_get_iter (priv->header_model,
1881 gtk_tree_row_reference_get_path (priv->row_reference));
1883 gtk_tree_model_get (priv->header_model, &iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1885 flags = tny_header_get_flags (header);
1886 gtk_tree_path_free (path);
1889 modest_msg_view_set_priority (MODEST_MSG_VIEW(priv->msg_view), flags);
1894 modest_msg_view_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1896 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1897 ModestWindowPrivate *parent_priv;
1898 ModestWindowMgr *mgr;
1899 gboolean is_fullscreen;
1900 GtkAction *fs_toggle_action;
1903 mgr = modest_runtime_get_window_mgr ();
1904 is_fullscreen = (modest_window_mgr_get_fullscreen_mode (mgr))?1:0;
1906 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1908 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1909 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1910 if (is_fullscreen != active) {
1911 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1920 set_homogeneous (GtkWidget *widget,
1923 if (GTK_IS_TOOL_ITEM (widget)) {
1924 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1925 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1930 modest_msg_view_window_show_toolbar (ModestWindow *self,
1931 gboolean show_toolbar)
1933 ModestMsgViewWindowPrivate *priv = NULL;
1934 ModestWindowPrivate *parent_priv;
1935 GtkWidget *reply_button = NULL, *menu = NULL;
1936 GtkWidget *placeholder = NULL;
1938 const gchar *action_name;
1941 parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1942 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
1944 /* Set optimized view status */
1945 priv->optimized_view = !show_toolbar;
1947 if (!parent_priv->toolbar) {
1948 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1950 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1952 /* Set homogeneous toolbar */
1953 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar),
1954 set_homogeneous, NULL);
1956 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1957 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1958 priv->next_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNext");
1959 priv->prev_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageBack");
1960 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1961 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1962 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1963 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1965 /* Add ProgressBar (Transfer toolbar) */
1966 priv->progress_bar = modest_progress_bar_widget_new ();
1967 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1968 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressbarView");
1969 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1970 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1971 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1973 /* Connect cancel 'clicked' signal to abort progress mode */
1974 g_signal_connect(priv->cancel_toolitem, "clicked",
1975 G_CALLBACK(cancel_progressbar),
1978 /* Add it to the observers list */
1979 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1982 hildon_window_add_toolbar (HILDON_WINDOW (self),
1983 GTK_TOOLBAR (parent_priv->toolbar));
1986 /* Set reply button tap and hold menu */
1987 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1988 "/ToolBar/ToolbarMessageReply");
1989 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1990 "/ToolbarReplyCSM");
1991 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1995 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
1996 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1997 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1999 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2000 set_toolbar_mode (MODEST_MSG_VIEW_WINDOW(self), TOOLBAR_MODE_NORMAL);
2003 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
2004 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
2007 /* Update also the actions (to update the toggles in the
2008 menus), we have to do it manually because some other window
2009 of the same time could have changed it (remember that the
2010 toolbar fullscreen mode is shared by all the windows of the
2012 if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
2013 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarFullScreenMenu";
2015 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMenu/ViewShowToolbarNormalScreenMenu";
2017 action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
2018 modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
2023 modest_msg_view_window_clipboard_owner_change (GtkClipboard *clipboard,
2025 ModestMsgViewWindow *window)
2027 if (!GTK_WIDGET_VISIBLE (window))
2030 modest_window_check_dimming_rules_group (MODEST_WINDOW (window), "ModestClipboardDimmingRules");
2034 modest_msg_view_window_transfer_mode_enabled (ModestMsgViewWindow *self)
2036 ModestMsgViewWindowPrivate *priv;
2038 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self), FALSE);
2039 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2041 return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2045 cancel_progressbar (GtkToolButton *toolbutton,
2046 ModestMsgViewWindow *self)
2049 ModestMsgViewWindowPrivate *priv;
2051 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2053 /* Get operation observers and cancel its current operation */
2054 tmp = priv->progress_widgets;
2056 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
2057 tmp=g_slist_next(tmp);
2061 observers_empty (ModestMsgViewWindow *self)
2064 ModestMsgViewWindowPrivate *priv;
2065 gboolean is_empty = TRUE;
2066 guint pending_ops = 0;
2068 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2069 tmp = priv->progress_widgets;
2071 /* Check all observers */
2072 while (tmp && is_empty) {
2073 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2074 is_empty = pending_ops == 0;
2076 tmp = g_slist_next(tmp);
2083 on_account_removed (TnyAccountStore *account_store,
2084 TnyAccount *account,
2087 /* Do nothing if it's a transport account, because we only
2088 show the messages of a store account */
2089 if (tny_account_get_account_type(account) == TNY_ACCOUNT_TYPE_STORE) {
2090 const gchar *parent_acc = NULL;
2091 const gchar *our_acc = NULL;
2093 our_acc = modest_window_get_active_account (MODEST_WINDOW (user_data));
2094 parent_acc = modest_tny_account_get_parent_modest_account_name_for_server_account (account);
2096 /* Close this window if I'm showing a message of the removed account */
2097 if (strcmp (parent_acc, our_acc) == 0)
2098 modest_ui_actions_on_close_window (NULL, MODEST_WINDOW (user_data));
2103 on_queue_changed (ModestMailOperationQueue *queue,
2104 ModestMailOperation *mail_op,
2105 ModestMailOperationQueueNotification type,
2106 ModestMsgViewWindow *self)
2109 ModestMsgViewWindowPrivate *priv;
2110 ModestMailOperationTypeOperation op_type;
2111 ModestToolBarModes mode;
2113 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (self));
2114 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self);
2116 /* If this operations was created by another window, do nothing */
2117 if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self)))
2120 /* Get toolbar mode from operation id*/
2121 op_type = modest_mail_operation_get_type_operation (mail_op);
2123 /* case MODEST_MAIL_OPERATION_TYPE_SEND: */
2124 case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2125 case MODEST_MAIL_OPERATION_TYPE_OPEN:
2126 mode = TOOLBAR_MODE_TRANSFER;
2129 mode = TOOLBAR_MODE_NORMAL;
2133 /* Add operation observers and change toolbar if neccessary*/
2134 tmp = priv->progress_widgets;
2136 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2137 if (mode == TOOLBAR_MODE_TRANSFER) {
2138 /* Enable transfer toolbar mode */
2139 set_toolbar_transfer_mode(self);
2141 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2143 tmp = g_slist_next (tmp);
2148 case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2149 if (mode == TOOLBAR_MODE_TRANSFER) {
2151 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2153 tmp = g_slist_next (tmp);
2157 /* If no more operations are being observed, NORMAL mode is enabled again */
2158 if (observers_empty (self)) {
2159 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
2167 modest_msg_view_window_get_attachments (ModestMsgViewWindow *win)
2169 ModestMsgViewWindowPrivate *priv;
2170 GList *selected_attachments = NULL;
2172 g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (win), NULL);
2173 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (win);
2175 selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2177 return selected_attachments;
2181 modest_msg_view_window_view_attachment (ModestMsgViewWindow *window, TnyMimePart *mime_part)
2183 ModestMsgViewWindowPrivate *priv;
2184 const gchar *msg_uid;
2185 gchar *attachment_uid = NULL;
2186 gint attachment_index = 0;
2189 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2190 g_return_if_fail (TNY_IS_MIME_PART (mime_part) || (mime_part == NULL));
2191 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2193 msg_uid = modest_msg_view_window_get_message_uid (MODEST_MSG_VIEW_WINDOW (window));
2194 attachments = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2195 attachment_index = g_list_index (attachments, mime_part);
2196 g_list_free (attachments);
2198 if (msg_uid && attachment_index >= 0) {
2199 attachment_uid = g_strdup_printf ("%s/%d", msg_uid, attachment_index);
2202 if (mime_part == NULL) {
2203 gboolean error = FALSE;
2204 GList *selected_attachments = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2205 if (selected_attachments == NULL) {
2207 } else if (g_list_length (selected_attachments) > 1) {
2208 hildon_banner_show_information (NULL, NULL, _("mcen_ib_unable_to_display_more"));
2211 mime_part = (TnyMimePart *) selected_attachments->data;
2212 g_object_ref (mime_part);
2214 g_list_foreach (selected_attachments, (GFunc) g_object_unref, NULL);
2215 g_list_free (selected_attachments);
2220 g_object_ref (mime_part);
2223 if (tny_mime_part_is_purged (mime_part)) {
2224 g_object_unref (mime_part);
2228 if (!TNY_IS_MSG (mime_part)) {
2229 gchar *filepath = NULL;
2230 const gchar *att_filename = tny_mime_part_get_filename (mime_part);
2231 TnyFsStream *temp_stream = NULL;
2232 temp_stream = modest_maemo_utils_create_temp_stream (att_filename, attachment_uid, &filepath);
2235 const gchar *content_type;
2236 content_type = tny_mime_part_get_content_type (mime_part);
2237 tny_mime_part_decode_to_stream (mime_part, TNY_STREAM (temp_stream));
2239 modest_platform_activate_file (filepath, content_type);
2240 g_object_unref (temp_stream);
2242 /* NOTE: files in the temporary area will be automatically
2243 * cleaned after some time if they are no longer in use */
2246 /* message attachment */
2247 TnyHeader *header = NULL;
2248 ModestWindowMgr *mgr;
2249 ModestWindow *msg_win = NULL;
2252 header = tny_msg_get_header (TNY_MSG (mime_part));
2253 mgr = modest_runtime_get_window_mgr ();
2254 found = modest_window_mgr_find_registered_header (mgr, header, &msg_win);
2257 if (msg_win) /* there is already a window for this uid; top it */
2258 gtk_window_present (GTK_WINDOW(msg_win));
2260 /* if it's found, but there is no msg_win, it's probably in the process of being created;
2261 * thus, we don't do anything */
2262 g_warning ("window for is already being created");
2264 /* it's not found, so create a new window for it */
2265 modest_window_mgr_register_header (mgr, header, attachment_uid); /* register the uid before building the window */
2266 gchar *account = g_strdup (modest_window_get_active_account (MODEST_WINDOW (window)));
2268 account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
2269 msg_win = modest_msg_view_window_new_for_attachment (TNY_MSG (mime_part), account, attachment_uid);
2270 modest_window_set_zoom (MODEST_WINDOW (msg_win),
2271 modest_window_get_zoom (MODEST_WINDOW (window)));
2272 modest_window_mgr_register_window (mgr, msg_win);
2273 gtk_window_set_transient_for (GTK_WINDOW (msg_win), GTK_WINDOW (window));
2274 gtk_widget_show_all (GTK_WIDGET (msg_win));
2277 g_object_unref (mime_part);
2293 static void save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct);
2294 static gboolean idle_save_mime_part_show_result (SaveMimePartInfo *info);
2295 static gpointer save_mime_part_to_file (SaveMimePartInfo *info);
2296 static void save_mime_parts_to_file_with_checks (SaveMimePartInfo *info);
2299 save_mime_part_info_free (SaveMimePartInfo *info, gboolean with_struct)
2303 for (node = info->pairs; node != NULL; node = g_list_next (node)) {
2304 SaveMimePartPair *pair = (SaveMimePartPair *) node->data;
2305 g_free (pair->filename);
2306 g_object_unref (pair->part);
2307 g_slice_free (SaveMimePartPair, pair);
2309 g_list_free (info->pairs);
2312 gtk_widget_destroy (info->banner);
2313 g_object_unref (info->banner);
2314 g_slice_free (SaveMimePartInfo, info);
2319 idle_save_mime_part_show_result (SaveMimePartInfo *info)
2321 if (info->pairs != NULL) {
2322 save_mime_part_to_file (info);
2325 result = info->result;
2327 /* This is a GDK lock because we are an idle callback and
2328 * hildon_banner_show_information is or does Gtk+ code */
2330 gdk_threads_enter (); /* CHECKED */
2331 save_mime_part_info_free (info, TRUE);
2333 hildon_banner_show_information (NULL, NULL, _CS("sfil_ib_saved"));
2335 hildon_banner_show_information (NULL, NULL, _("mail_ib_file_operation_failed"));
2337 gdk_threads_leave (); /* CHECKED */
2344 save_mime_part_to_file (SaveMimePartInfo *info)
2346 GnomeVFSResult result;
2347 GnomeVFSHandle *handle;
2349 SaveMimePartPair *pair = (SaveMimePartPair *) info->pairs->data;
2351 result = gnome_vfs_create (&handle, pair->filename, GNOME_VFS_OPEN_WRITE, FALSE, 0444);
2352 if (result == GNOME_VFS_OK) {
2353 stream = tny_vfs_stream_new (handle);
2354 tny_mime_part_decode_to_stream (pair->part, stream);
2355 g_object_unref (G_OBJECT (stream));
2356 g_object_unref (pair->part);
2357 g_slice_free (SaveMimePartPair, pair);
2358 info->pairs = g_list_delete_link (info->pairs, info->pairs);
2359 info->result = TRUE;
2361 save_mime_part_info_free (info, FALSE);
2362 info->result = FALSE;
2365 g_idle_add ((GSourceFunc) idle_save_mime_part_show_result, info);
2370 save_mime_parts_to_file_with_checks (SaveMimePartInfo *info)
2372 gboolean is_ok = TRUE;
2373 gint replaced_files = 0;
2374 const GList *files = info->pairs;
2377 for (iter = files; (iter != NULL) && (replaced_files < 2); iter = g_list_next(iter)) {
2378 SaveMimePartPair *pair = iter->data;
2379 if (modest_maemo_utils_file_exists (pair->filename)) {
2383 if (replaced_files) {
2384 GtkWidget *confirm_overwrite_dialog;
2385 const gchar *message = (replaced_files == 1) ?
2386 _FM("docm_nc_replace_file") : _FM("docm_nc_replace_multiple");
2387 confirm_overwrite_dialog = hildon_note_new_confirmation (NULL, message);
2388 if (gtk_dialog_run (GTK_DIALOG (confirm_overwrite_dialog)) != GTK_RESPONSE_OK) {
2391 gtk_widget_destroy (confirm_overwrite_dialog);
2395 save_mime_part_info_free (info, TRUE);
2397 GtkWidget *banner = hildon_banner_show_animation (NULL, NULL,
2398 _CS("sfil_ib_saving"));
2399 info->banner = g_object_ref (banner);
2400 g_thread_create ((GThreadFunc)save_mime_part_to_file, info, FALSE, NULL);
2401 g_object_unref (banner);
2408 modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, GList *mime_parts)
2410 gboolean clean_list = FALSE;
2411 ModestMsgViewWindowPrivate *priv;
2412 GList *files_to_save = NULL;
2413 GtkWidget *save_dialog = NULL;
2414 gchar *folder = NULL;
2415 gboolean canceled = FALSE;
2416 const gchar *filename = NULL;
2417 gchar *save_multiple_str = NULL;
2419 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2420 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2422 if (mime_parts == NULL) {
2423 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2424 if (mime_parts == NULL)
2429 /* prepare dialog */
2430 if (mime_parts->next == NULL) {
2431 /* only one attachment selected */
2432 TnyMimePart *mime_part = (TnyMimePart *) mime_parts->data;
2433 if (!TNY_IS_MSG (mime_part) && tny_mime_part_is_attachment (mime_part)) {
2434 filename = tny_mime_part_get_filename (mime_part);
2436 g_warning ("Tried to save a non-file attachment");
2440 save_multiple_str = g_strdup_printf (_FM("sfil_va_number_of_objects_attachments"),
2441 g_list_length (mime_parts));
2444 save_dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window),
2445 GTK_FILE_CHOOSER_ACTION_SAVE);
2448 folder = g_build_filename (g_get_home_dir (), DEFAULT_FOLDER, NULL);
2449 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (save_dialog), folder);
2453 if (filename != NULL)
2454 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog),
2457 /* if multiple, set multiple string */
2458 if (save_multiple_str) {
2459 g_object_set (G_OBJECT (save_dialog), "save-multiple", save_multiple_str, NULL);
2463 if (gtk_dialog_run (GTK_DIALOG (save_dialog)) == GTK_RESPONSE_OK) {
2464 gchar *chooser_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (save_dialog));
2466 if (!modest_maemo_utils_folder_writable (chooser_uri)) {
2467 hildon_banner_show_information
2468 (NULL, NULL, dgettext("hildon-fm", "sfil_ib_readonly_location"));
2472 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2473 TnyMimePart *mime_part = (TnyMimePart *) node->data;
2475 if (tny_mime_part_is_attachment (mime_part)) {
2476 SaveMimePartPair *pair;
2478 if ((mime_parts->next != NULL) &&
2479 (tny_mime_part_get_filename (mime_part) == NULL))
2482 pair = g_slice_new0 (SaveMimePartPair);
2483 if (mime_parts->next == NULL) {
2484 pair->filename = g_strdup (chooser_uri);
2487 g_build_filename (chooser_uri,
2488 tny_mime_part_get_filename (mime_part), NULL);
2490 pair->part = g_object_ref (mime_part);
2491 files_to_save = g_list_prepend (files_to_save, pair);
2495 g_free (chooser_uri);
2498 gtk_widget_destroy (save_dialog);
2501 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2502 g_list_free (mime_parts);
2505 if (files_to_save != NULL) {
2506 SaveMimePartInfo *info = g_slice_new0 (SaveMimePartInfo);
2507 info->pairs = files_to_save;
2508 info->result = TRUE;
2509 save_mime_parts_to_file_with_checks (info);
2514 show_remove_attachment_information (gpointer userdata)
2516 ModestMsgViewWindow *window = (ModestMsgViewWindow *) userdata;
2517 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2519 /* We're outside the main lock */
2520 gdk_threads_enter ();
2522 if (priv->remove_attachment_banner != NULL) {
2523 gtk_widget_destroy (priv->remove_attachment_banner);
2524 g_object_unref (priv->remove_attachment_banner);
2527 priv->remove_attachment_banner = g_object_ref (
2528 hildon_banner_show_animation (NULL, NULL, _("mcen_ib_removing_attachment")));
2530 gdk_threads_leave ();
2536 modest_msg_view_window_remove_attachments (ModestMsgViewWindow *window, gboolean get_all)
2538 ModestMsgViewWindowPrivate *priv;
2539 GList *mime_parts = NULL, *node;
2540 gchar *confirmation_message;
2544 /* TnyFolder *folder; */
2546 g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window));
2547 priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2550 mime_parts = modest_msg_view_get_attachments (MODEST_MSG_VIEW (priv->msg_view));
2552 mime_parts = modest_msg_view_get_selected_attachments (MODEST_MSG_VIEW (priv->msg_view));
2554 /* Remove already purged messages from mime parts list */
2556 while (node != NULL) {
2557 TnyMimePart *part = TNY_MIME_PART (node->data);
2558 if (tny_mime_part_is_purged (part)) {
2559 GList *deleted_node = node;
2560 node = g_list_next (node);
2561 g_object_unref (part);
2562 mime_parts = g_list_delete_link (mime_parts, deleted_node);
2564 node = g_list_next (node);
2568 if (mime_parts == NULL)
2571 n_attachments = g_list_length (mime_parts);
2572 if (n_attachments == 1) {
2573 const gchar *filename;
2575 if (TNY_IS_MSG (mime_parts->data)) {
2577 header = tny_msg_get_header (TNY_MSG (mime_parts->data));
2578 filename = tny_header_get_subject (header);
2579 g_object_unref (header);
2580 if (filename == NULL)
2581 filename = _("mail_va_no_subject");
2583 filename = tny_mime_part_get_filename (TNY_MIME_PART (mime_parts->data));
2585 confirmation_message = g_strdup_printf (_("mcen_nc_purge_file_text"), filename);
2587 confirmation_message = g_strdup_printf (ngettext("mcen_nc_purge_file_text",
2588 "mcen_nc_purge_files_text",
2589 n_attachments), n_attachments);
2591 response = modest_platform_run_confirmation_dialog (GTK_WINDOW (window),
2592 confirmation_message);
2593 g_free (confirmation_message);
2595 if (response != GTK_RESPONSE_OK)
2598 priv->purge_timeout = g_timeout_add (2000, show_remove_attachment_information, window);
2599 /* folder = tny_msg_get_folder (msg); */
2600 /* tny_msg_uncache_attachments (msg); */
2601 /* tny_folder_refresh (folder, NULL); */
2602 /* g_object_unref (folder); */
2604 for (node = mime_parts; node != NULL; node = g_list_next (node)) {
2605 tny_mime_part_set_purged (TNY_MIME_PART (node->data));
2606 /* modest_msg_view_remove_attachment (MODEST_MSG_VIEW (priv->msg_view), node->data); */
2609 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2610 tny_msg_view_clear (TNY_MSG_VIEW (priv->msg_view));
2611 tny_msg_rewrite_cache (msg);
2612 tny_msg_view_set_msg (TNY_MSG_VIEW (priv->msg_view), msg);
2614 g_list_foreach (mime_parts, (GFunc) g_object_unref, NULL);
2615 g_list_free (mime_parts);
2617 if (priv->purge_timeout > 0) {
2618 g_source_remove (priv->purge_timeout);
2619 priv->purge_timeout = 0;
2622 if (priv->remove_attachment_banner) {
2623 gtk_widget_destroy (priv->remove_attachment_banner);
2624 g_object_unref (priv->remove_attachment_banner);
2625 priv->remove_attachment_banner = NULL;
2633 update_window_title (ModestMsgViewWindow *window)
2635 ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window);
2637 TnyHeader *header = NULL;
2638 const gchar *subject = NULL;
2640 msg = tny_msg_view_get_msg (TNY_MSG_VIEW (priv->msg_view));
2643 header = tny_msg_get_header (msg);
2644 subject = tny_header_get_subject (header);
2645 g_object_unref (msg);
2648 if ((subject == NULL)||(subject[0] == '\0'))
2649 subject = _("mail_va_no_subject");
2651 gtk_window_set_title (GTK_WINDOW (window), subject);
2655 static void on_move_focus (ModestMsgViewWindow *window,
2656 GtkDirectionType direction,
2659 GtkWidget *current_focus = NULL;
2661 current_focus = gtk_window_get_focus (GTK_WINDOW (window));
2662 if ((current_focus != NULL) &&
2663 MODEST_IS_ATTACHMENTS_VIEW (current_focus)) {
2664 g_signal_stop_emission_by_name (G_OBJECT (window), "move-focus");